2012-02-18 12:03:15 +00:00
|
|
|
//===-- ARMBaseInstrInfo.cpp - ARM Instruction Information ----------------===//
|
2009-07-08 16:09:28 +00:00
|
|
|
//
|
2019-01-19 08:50:56 +00:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2009-07-08 16:09:28 +00:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file contains the Base ARM implementation of the TargetInstrInfo class.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2013-10-03 09:31:51 +00:00
|
|
|
#include "ARMBaseInstrInfo.h"
|
2012-03-26 00:45:15 +00:00
|
|
|
#include "ARMBaseRegisterInfo.h"
|
2009-11-07 04:04:34 +00:00
|
|
|
#include "ARMConstantPoolValue.h"
|
2013-10-03 09:31:51 +00:00
|
|
|
#include "ARMFeatures.h"
|
2010-12-05 22:04:16 +00:00
|
|
|
#include "ARMHazardRecognizer.h"
|
2009-07-08 16:09:28 +00:00
|
|
|
#include "ARMMachineFunctionInfo.h"
|
2017-01-26 23:40:06 +00:00
|
|
|
#include "ARMSubtarget.h"
|
2011-07-20 23:34:39 +00:00
|
|
|
#include "MCTargetDesc/ARMAddressingModes.h"
|
2017-01-26 23:40:06 +00:00
|
|
|
#include "MCTargetDesc/ARMBaseInfo.h"
|
|
|
|
#include "llvm/ADT/DenseMap.h"
|
2017-06-06 11:49:48 +00:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
2017-01-26 23:40:06 +00:00
|
|
|
#include "llvm/ADT/SmallSet.h"
|
|
|
|
#include "llvm/ADT/SmallVector.h"
|
|
|
|
#include "llvm/ADT/Triple.h"
|
2009-07-08 16:09:28 +00:00
|
|
|
#include "llvm/CodeGen/LiveVariables.h"
|
2017-01-26 23:40:06 +00:00
|
|
|
#include "llvm/CodeGen/MachineBasicBlock.h"
|
2009-11-07 04:04:34 +00:00
|
|
|
#include "llvm/CodeGen/MachineConstantPool.h"
|
2009-07-08 16:09:28 +00:00
|
|
|
#include "llvm/CodeGen/MachineFrameInfo.h"
|
2017-01-26 23:40:06 +00:00
|
|
|
#include "llvm/CodeGen/MachineFunction.h"
|
|
|
|
#include "llvm/CodeGen/MachineInstr.h"
|
2009-07-08 16:09:28 +00:00
|
|
|
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
2009-10-07 00:06:35 +00:00
|
|
|
#include "llvm/CodeGen/MachineMemOperand.h"
|
2020-05-15 08:44:23 +02:00
|
|
|
#include "llvm/CodeGen/MachineModuleInfo.h"
|
2017-01-26 23:40:06 +00:00
|
|
|
#include "llvm/CodeGen/MachineOperand.h"
|
2010-05-22 01:47:14 +00:00
|
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
2017-01-26 23:40:06 +00:00
|
|
|
#include "llvm/CodeGen/ScoreboardHazardRecognizer.h"
|
2011-07-20 23:34:39 +00:00
|
|
|
#include "llvm/CodeGen/SelectionDAGNodes.h"
|
2017-11-08 01:01:31 +00:00
|
|
|
#include "llvm/CodeGen/TargetInstrInfo.h"
|
2017-11-17 01:07:10 +00:00
|
|
|
#include "llvm/CodeGen/TargetRegisterInfo.h"
|
2015-06-13 03:42:11 +00:00
|
|
|
#include "llvm/CodeGen/TargetSchedule.h"
|
2017-01-26 23:40:06 +00:00
|
|
|
#include "llvm/IR/Attributes.h"
|
2013-01-02 11:36:10 +00:00
|
|
|
#include "llvm/IR/Constants.h"
|
2017-01-26 23:40:06 +00:00
|
|
|
#include "llvm/IR/DebugLoc.h"
|
2013-01-02 11:36:10 +00:00
|
|
|
#include "llvm/IR/Function.h"
|
|
|
|
#include "llvm/IR/GlobalValue.h"
|
2009-08-22 20:48:53 +00:00
|
|
|
#include "llvm/MC/MCAsmInfo.h"
|
2017-01-26 23:40:06 +00:00
|
|
|
#include "llvm/MC/MCInstrDesc.h"
|
|
|
|
#include "llvm/MC/MCInstrItineraries.h"
|
2011-07-10 02:58:07 +00:00
|
|
|
#include "llvm/Support/BranchProbability.h"
|
2017-01-26 23:40:06 +00:00
|
|
|
#include "llvm/Support/Casting.h"
|
2009-07-08 16:09:28 +00:00
|
|
|
#include "llvm/Support/CommandLine.h"
|
2017-01-26 23:40:06 +00:00
|
|
|
#include "llvm/Support/Compiler.h"
|
2009-11-02 00:10:38 +00:00
|
|
|
#include "llvm/Support/Debug.h"
|
2009-07-11 20:10:48 +00:00
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
2015-03-23 19:32:43 +00:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2017-01-26 23:40:06 +00:00
|
|
|
#include "llvm/Target/TargetMachine.h"
|
|
|
|
#include <algorithm>
|
|
|
|
#include <cassert>
|
|
|
|
#include <cstdint>
|
|
|
|
#include <iterator>
|
|
|
|
#include <new>
|
|
|
|
#include <utility>
|
|
|
|
#include <vector>
|
2011-06-28 20:07:07 +00:00
|
|
|
|
2009-07-08 16:09:28 +00:00
|
|
|
using namespace llvm;
|
|
|
|
|
2014-04-21 22:55:11 +00:00
|
|
|
#define DEBUG_TYPE "arm-instrinfo"
|
|
|
|
|
2014-04-22 02:03:14 +00:00
|
|
|
#define GET_INSTRINFO_CTOR_DTOR
|
|
|
|
#include "ARMGenInstrInfo.inc"
|
|
|
|
|
2009-07-08 16:09:28 +00:00
|
|
|
static cl::opt<bool>
|
|
|
|
EnableARM3Addr("enable-arm-3-addr-conv", cl::Hidden,
|
|
|
|
cl::desc("Enable ARM 2-addr to 3-addr conv"));
|
|
|
|
|
2010-12-05 22:04:16 +00:00
|
|
|
/// ARM_MLxEntry - Record information about MLA / MLS instructions.
|
|
|
|
struct ARM_MLxEntry {
|
2012-05-24 03:59:11 +00:00
|
|
|
uint16_t MLxOpc; // MLA / MLS opcode
|
|
|
|
uint16_t MulOpc; // Expanded multiplication opcode
|
|
|
|
uint16_t AddSubOpc; // Expanded add / sub opcode
|
2010-12-05 22:04:16 +00:00
|
|
|
bool NegAcc; // True if the acc is negated before the add / sub.
|
|
|
|
bool HasLane; // True if instruction has an extra "lane" operand.
|
|
|
|
};
|
|
|
|
|
|
|
|
static const ARM_MLxEntry ARM_MLxTable[] = {
|
|
|
|
// MLxOpc, MulOpc, AddSubOpc, NegAcc, HasLane
|
|
|
|
// fp scalar ops
|
|
|
|
{ ARM::VMLAS, ARM::VMULS, ARM::VADDS, false, false },
|
|
|
|
{ ARM::VMLSS, ARM::VMULS, ARM::VSUBS, false, false },
|
|
|
|
{ ARM::VMLAD, ARM::VMULD, ARM::VADDD, false, false },
|
|
|
|
{ ARM::VMLSD, ARM::VMULD, ARM::VSUBD, false, false },
|
|
|
|
{ ARM::VNMLAS, ARM::VNMULS, ARM::VSUBS, true, false },
|
|
|
|
{ ARM::VNMLSS, ARM::VMULS, ARM::VSUBS, true, false },
|
|
|
|
{ ARM::VNMLAD, ARM::VNMULD, ARM::VSUBD, true, false },
|
|
|
|
{ ARM::VNMLSD, ARM::VMULD, ARM::VSUBD, true, false },
|
|
|
|
|
|
|
|
// fp SIMD ops
|
|
|
|
{ ARM::VMLAfd, ARM::VMULfd, ARM::VADDfd, false, false },
|
|
|
|
{ ARM::VMLSfd, ARM::VMULfd, ARM::VSUBfd, false, false },
|
|
|
|
{ ARM::VMLAfq, ARM::VMULfq, ARM::VADDfq, false, false },
|
|
|
|
{ ARM::VMLSfq, ARM::VMULfq, ARM::VSUBfq, false, false },
|
|
|
|
{ ARM::VMLAslfd, ARM::VMULslfd, ARM::VADDfd, false, true },
|
|
|
|
{ ARM::VMLSslfd, ARM::VMULslfd, ARM::VSUBfd, false, true },
|
|
|
|
{ ARM::VMLAslfq, ARM::VMULslfq, ARM::VADDfq, false, true },
|
|
|
|
{ ARM::VMLSslfq, ARM::VMULslfq, ARM::VSUBfq, false, true },
|
|
|
|
};
|
|
|
|
|
2009-11-02 00:10:38 +00:00
|
|
|
ARMBaseInstrInfo::ARMBaseInstrInfo(const ARMSubtarget& STI)
|
2011-07-01 17:57:27 +00:00
|
|
|
: ARMGenInstrInfo(ARM::ADJCALLSTACKDOWN, ARM::ADJCALLSTACKUP),
|
2009-11-02 00:10:38 +00:00
|
|
|
Subtarget(STI) {
|
2010-12-05 22:04:16 +00:00
|
|
|
for (unsigned i = 0, e = array_lengthof(ARM_MLxTable); i != e; ++i) {
|
|
|
|
if (!MLxEntryMap.insert(std::make_pair(ARM_MLxTable[i].MLxOpc, i)).second)
|
2015-10-25 22:28:27 +00:00
|
|
|
llvm_unreachable("Duplicated entries?");
|
2010-12-05 22:04:16 +00:00
|
|
|
MLxHazardOpcodes.insert(ARM_MLxTable[i].AddSubOpc);
|
|
|
|
MLxHazardOpcodes.insert(ARM_MLxTable[i].MulOpc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Various bits of framework needed for precise machine-level selection
DAG scheduling during isel. Most new functionality is currently
guarded by -enable-sched-cycles and -enable-sched-hazard.
Added InstrItineraryData::IssueWidth field, currently derived from
ARM itineraries, but could be initialized differently on other targets.
Added ScheduleHazardRecognizer::MaxLookAhead to indicate whether it is
active, and if so how many cycles of state it holds.
Added SchedulingPriorityQueue::HasReadyFilter to allowing gating entry
into the scheduler's available queue.
ScoreboardHazardRecognizer now accesses the ScheduleDAG in order to
get information about it's SUnits, provides RecedeCycle for bottom-up
scheduling, correctly computes scoreboard depth, tracks IssueCount, and
considers potential stall cycles when checking for hazards.
ScheduleDAGRRList now models machine cycles and hazards (under
flags). It tracks MinAvailableCycle, drives the hazard recognizer and
priority queue's ready filter, manages a new PendingQueue, properly
accounts for stall cycles, etc.
llvm-svn: 122541
2010-12-24 05:03:26 +00:00
|
|
|
// Use a ScoreboardHazardRecognizer for prepass ARM scheduling. TargetInstrImpl
|
|
|
|
// currently defaults to no prepass hazard recognizer.
|
2014-06-13 22:38:52 +00:00
|
|
|
ScheduleHazardRecognizer *
|
|
|
|
ARMBaseInstrInfo::CreateTargetHazardRecognizer(const TargetSubtargetInfo *STI,
|
|
|
|
const ScheduleDAG *DAG) const {
|
2011-01-21 05:51:33 +00:00
|
|
|
if (usePreRAHazardRecognizer()) {
|
2014-06-13 22:38:52 +00:00
|
|
|
const InstrItineraryData *II =
|
2014-08-04 21:25:23 +00:00
|
|
|
static_cast<const ARMSubtarget *>(STI)->getInstrItineraryData();
|
Various bits of framework needed for precise machine-level selection
DAG scheduling during isel. Most new functionality is currently
guarded by -enable-sched-cycles and -enable-sched-hazard.
Added InstrItineraryData::IssueWidth field, currently derived from
ARM itineraries, but could be initialized differently on other targets.
Added ScheduleHazardRecognizer::MaxLookAhead to indicate whether it is
active, and if so how many cycles of state it holds.
Added SchedulingPriorityQueue::HasReadyFilter to allowing gating entry
into the scheduler's available queue.
ScoreboardHazardRecognizer now accesses the ScheduleDAG in order to
get information about it's SUnits, provides RecedeCycle for bottom-up
scheduling, correctly computes scoreboard depth, tracks IssueCount, and
considers potential stall cycles when checking for hazards.
ScheduleDAGRRList now models machine cycles and hazards (under
flags). It tracks MinAvailableCycle, drives the hazard recognizer and
priority queue's ready filter, manages a new PendingQueue, properly
accounts for stall cycles, etc.
llvm-svn: 122541
2010-12-24 05:03:26 +00:00
|
|
|
return new ScoreboardHazardRecognizer(II, DAG, "pre-RA-sched");
|
|
|
|
}
|
2014-06-13 22:38:52 +00:00
|
|
|
return TargetInstrInfo::CreateTargetHazardRecognizer(STI, DAG);
|
Various bits of framework needed for precise machine-level selection
DAG scheduling during isel. Most new functionality is currently
guarded by -enable-sched-cycles and -enable-sched-hazard.
Added InstrItineraryData::IssueWidth field, currently derived from
ARM itineraries, but could be initialized differently on other targets.
Added ScheduleHazardRecognizer::MaxLookAhead to indicate whether it is
active, and if so how many cycles of state it holds.
Added SchedulingPriorityQueue::HasReadyFilter to allowing gating entry
into the scheduler's available queue.
ScoreboardHazardRecognizer now accesses the ScheduleDAG in order to
get information about it's SUnits, provides RecedeCycle for bottom-up
scheduling, correctly computes scoreboard depth, tracks IssueCount, and
considers potential stall cycles when checking for hazards.
ScheduleDAGRRList now models machine cycles and hazards (under
flags). It tracks MinAvailableCycle, drives the hazard recognizer and
priority queue's ready filter, manages a new PendingQueue, properly
accounts for stall cycles, etc.
llvm-svn: 122541
2010-12-24 05:03:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ScheduleHazardRecognizer *ARMBaseInstrInfo::
|
|
|
|
CreateTargetPostRAHazardRecognizer(const InstrItineraryData *II,
|
|
|
|
const ScheduleDAG *DAG) const {
|
[ARM] Replace fp-only-sp and d16 with fp64 and d32.
Those two subtarget features were awkward because their semantics are
reversed: each one indicates the _lack_ of support for something in
the architecture, rather than the presence. As a consequence, you
don't get the behavior you want if you combine two sets of feature
bits.
Each SubtargetFeature for an FP architecture version now comes in four
versions, one for each combination of those options. So you can still
say (for example) '+vfp2' in a feature string and it will mean what
it's always meant, but there's a new string '+vfp2d16sp' meaning the
version without those extra options.
A lot of this change is just mechanically replacing positive checks
for the old features with negative checks for the new ones. But one
more interesting change is that I've rearranged getFPUFeatures() so
that the main FPU feature is appended to the output list *before*
rather than after the features derived from the Restriction field, so
that -fp64 and -d32 can override defaults added by the main feature.
Reviewers: dmgreen, samparker, SjoerdMeijer
Subscribers: srhines, javed.absar, eraman, kristof.beyls, hiraditya, zzheng, Petar.Avramovic, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D60691
llvm-svn: 361845
2019-05-28 16:13:20 +00:00
|
|
|
if (Subtarget.isThumb2() || Subtarget.hasVFP2Base())
|
2020-01-09 13:57:53 +00:00
|
|
|
return new ARMHazardRecognizer(II, DAG);
|
2012-11-28 02:35:17 +00:00
|
|
|
return TargetInstrInfo::CreateTargetPostRAHazardRecognizer(II, DAG);
|
2009-07-08 16:09:28 +00:00
|
|
|
}
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
MachineInstr *ARMBaseInstrInfo::convertToThreeAddress(
|
|
|
|
MachineFunction::iterator &MFI, MachineInstr &MI, LiveVariables *LV) const {
|
2009-07-27 18:44:00 +00:00
|
|
|
// FIXME: Thumb2 support.
|
|
|
|
|
2009-07-08 16:09:28 +00:00
|
|
|
if (!EnableARM3Addr)
|
2014-04-25 05:30:21 +00:00
|
|
|
return nullptr;
|
2009-07-08 16:09:28 +00:00
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
MachineFunction &MF = *MI.getParent()->getParent();
|
|
|
|
uint64_t TSFlags = MI.getDesc().TSFlags;
|
2009-07-08 16:09:28 +00:00
|
|
|
bool isPre = false;
|
|
|
|
switch ((TSFlags & ARMII::IndexModeMask) >> ARMII::IndexModeShift) {
|
2014-04-25 05:30:21 +00:00
|
|
|
default: return nullptr;
|
2009-07-08 16:09:28 +00:00
|
|
|
case ARMII::IndexModePre:
|
|
|
|
isPre = true;
|
|
|
|
break;
|
|
|
|
case ARMII::IndexModePost:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Try splitting an indexed load/store to an un-indexed one plus an add/sub
|
|
|
|
// operation.
|
2016-06-30 00:01:54 +00:00
|
|
|
unsigned MemOpc = getUnindexedOpcode(MI.getOpcode());
|
2009-07-08 16:09:28 +00:00
|
|
|
if (MemOpc == 0)
|
2014-04-25 05:30:21 +00:00
|
|
|
return nullptr;
|
2009-07-08 16:09:28 +00:00
|
|
|
|
2014-04-25 05:30:21 +00:00
|
|
|
MachineInstr *UpdateMI = nullptr;
|
|
|
|
MachineInstr *MemMI = nullptr;
|
2009-07-08 16:09:28 +00:00
|
|
|
unsigned AddrMode = (TSFlags & ARMII::AddrModeMask);
|
2016-06-30 00:01:54 +00:00
|
|
|
const MCInstrDesc &MCID = MI.getDesc();
|
2011-06-28 19:10:37 +00:00
|
|
|
unsigned NumOps = MCID.getNumOperands();
|
2016-06-30 00:01:54 +00:00
|
|
|
bool isLoad = !MI.mayStore();
|
|
|
|
const MachineOperand &WB = isLoad ? MI.getOperand(1) : MI.getOperand(0);
|
|
|
|
const MachineOperand &Base = MI.getOperand(2);
|
|
|
|
const MachineOperand &Offset = MI.getOperand(NumOps - 3);
|
Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Partial reverts in:
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
X86FixupLEAs.cpp - Some functions return unsigned and arguably should be MCRegister
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
HexagonBitSimplify.cpp - Function takes BitTracker::RegisterRef which appears to be unsigned&
MachineVerifier.cpp - Ambiguous operator==() given MCRegister and const Register
PPCFastISel.cpp - No Register::operator-=()
PeepholeOptimizer.cpp - TargetInstrInfo::optimizeLoadInstr() takes an unsigned&
MachineTraceMetrics.cpp - MachineTraceMetrics lacks a suitable constructor
Manual fixups in:
ARMFastISel.cpp - ARMEmitLoad() now takes a Register& instead of unsigned&
HexagonSplitDouble.cpp - Ternary operator was ambiguous between unsigned/Register
HexagonConstExtenders.cpp - Has a local class named Register, used llvm::Register instead of Register.
PPCFastISel.cpp - PPCEmitLoad() now takes a Register& instead of unsigned&
Depends on D65919
Reviewers: arsenm, bogner, craig.topper, RKSimon
Reviewed By: arsenm
Subscribers: RKSimon, craig.topper, lenary, aemerson, wuzish, jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65962
llvm-svn: 369041
2019-08-15 19:22:08 +00:00
|
|
|
Register WBReg = WB.getReg();
|
|
|
|
Register BaseReg = Base.getReg();
|
|
|
|
Register OffReg = Offset.getReg();
|
2016-06-30 00:01:54 +00:00
|
|
|
unsigned OffImm = MI.getOperand(NumOps - 2).getImm();
|
|
|
|
ARMCC::CondCodes Pred = (ARMCC::CondCodes)MI.getOperand(NumOps - 1).getImm();
|
2009-07-08 16:09:28 +00:00
|
|
|
switch (AddrMode) {
|
2012-02-07 02:50:20 +00:00
|
|
|
default: llvm_unreachable("Unknown indexed op!");
|
2009-07-08 16:09:28 +00:00
|
|
|
case ARMII::AddrMode2: {
|
|
|
|
bool isSub = ARM_AM::getAM2Op(OffImm) == ARM_AM::sub;
|
|
|
|
unsigned Amt = ARM_AM::getAM2Offset(OffImm);
|
|
|
|
if (OffReg == 0) {
|
2009-07-08 21:03:57 +00:00
|
|
|
if (ARM_AM::getSOImmVal(Amt) == -1)
|
2009-07-08 16:09:28 +00:00
|
|
|
// Can't encode it in a so_imm operand. This transformation will
|
|
|
|
// add more than 1 instruction. Abandon!
|
2014-04-25 05:30:21 +00:00
|
|
|
return nullptr;
|
2016-06-30 00:01:54 +00:00
|
|
|
UpdateMI = BuildMI(MF, MI.getDebugLoc(),
|
2009-07-27 18:44:00 +00:00
|
|
|
get(isSub ? ARM::SUBri : ARM::ADDri), WBReg)
|
2016-06-30 00:01:54 +00:00
|
|
|
.addReg(BaseReg)
|
|
|
|
.addImm(Amt)
|
2017-01-20 08:15:24 +00:00
|
|
|
.add(predOps(Pred))
|
|
|
|
.add(condCodeOp());
|
2009-07-08 16:09:28 +00:00
|
|
|
} else if (Amt != 0) {
|
|
|
|
ARM_AM::ShiftOpc ShOpc = ARM_AM::getAM2ShiftOpc(OffImm);
|
|
|
|
unsigned SOOpc = ARM_AM::getSORegOpc(ShOpc, Amt);
|
2016-06-30 00:01:54 +00:00
|
|
|
UpdateMI = BuildMI(MF, MI.getDebugLoc(),
|
2011-07-21 18:54:16 +00:00
|
|
|
get(isSub ? ARM::SUBrsi : ARM::ADDrsi), WBReg)
|
2016-06-30 00:01:54 +00:00
|
|
|
.addReg(BaseReg)
|
|
|
|
.addReg(OffReg)
|
|
|
|
.addReg(0)
|
|
|
|
.addImm(SOOpc)
|
2017-01-20 08:15:24 +00:00
|
|
|
.add(predOps(Pred))
|
|
|
|
.add(condCodeOp());
|
2009-07-08 16:09:28 +00:00
|
|
|
} else
|
2016-06-30 00:01:54 +00:00
|
|
|
UpdateMI = BuildMI(MF, MI.getDebugLoc(),
|
2009-07-27 18:44:00 +00:00
|
|
|
get(isSub ? ARM::SUBrr : ARM::ADDrr), WBReg)
|
2016-06-30 00:01:54 +00:00
|
|
|
.addReg(BaseReg)
|
|
|
|
.addReg(OffReg)
|
2017-01-20 08:15:24 +00:00
|
|
|
.add(predOps(Pred))
|
|
|
|
.add(condCodeOp());
|
2009-07-08 16:09:28 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case ARMII::AddrMode3 : {
|
|
|
|
bool isSub = ARM_AM::getAM3Op(OffImm) == ARM_AM::sub;
|
|
|
|
unsigned Amt = ARM_AM::getAM3Offset(OffImm);
|
|
|
|
if (OffReg == 0)
|
|
|
|
// Immediate is 8-bits. It's guaranteed to fit in a so_imm operand.
|
2016-06-30 00:01:54 +00:00
|
|
|
UpdateMI = BuildMI(MF, MI.getDebugLoc(),
|
2009-07-27 18:44:00 +00:00
|
|
|
get(isSub ? ARM::SUBri : ARM::ADDri), WBReg)
|
2016-06-30 00:01:54 +00:00
|
|
|
.addReg(BaseReg)
|
|
|
|
.addImm(Amt)
|
2017-01-20 08:15:24 +00:00
|
|
|
.add(predOps(Pred))
|
|
|
|
.add(condCodeOp());
|
2009-07-08 16:09:28 +00:00
|
|
|
else
|
2016-06-30 00:01:54 +00:00
|
|
|
UpdateMI = BuildMI(MF, MI.getDebugLoc(),
|
2009-07-27 18:44:00 +00:00
|
|
|
get(isSub ? ARM::SUBrr : ARM::ADDrr), WBReg)
|
2016-06-30 00:01:54 +00:00
|
|
|
.addReg(BaseReg)
|
|
|
|
.addReg(OffReg)
|
2017-01-20 08:15:24 +00:00
|
|
|
.add(predOps(Pred))
|
|
|
|
.add(condCodeOp());
|
2009-07-08 16:09:28 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<MachineInstr*> NewMIs;
|
|
|
|
if (isPre) {
|
|
|
|
if (isLoad)
|
2016-06-30 00:01:54 +00:00
|
|
|
MemMI =
|
|
|
|
BuildMI(MF, MI.getDebugLoc(), get(MemOpc), MI.getOperand(0).getReg())
|
|
|
|
.addReg(WBReg)
|
|
|
|
.addImm(0)
|
|
|
|
.addImm(Pred);
|
2009-07-08 16:09:28 +00:00
|
|
|
else
|
2016-06-30 00:01:54 +00:00
|
|
|
MemMI = BuildMI(MF, MI.getDebugLoc(), get(MemOpc))
|
|
|
|
.addReg(MI.getOperand(1).getReg())
|
|
|
|
.addReg(WBReg)
|
|
|
|
.addReg(0)
|
|
|
|
.addImm(0)
|
|
|
|
.addImm(Pred);
|
2009-07-08 16:09:28 +00:00
|
|
|
NewMIs.push_back(MemMI);
|
|
|
|
NewMIs.push_back(UpdateMI);
|
|
|
|
} else {
|
|
|
|
if (isLoad)
|
2016-06-30 00:01:54 +00:00
|
|
|
MemMI =
|
|
|
|
BuildMI(MF, MI.getDebugLoc(), get(MemOpc), MI.getOperand(0).getReg())
|
|
|
|
.addReg(BaseReg)
|
|
|
|
.addImm(0)
|
|
|
|
.addImm(Pred);
|
2009-07-08 16:09:28 +00:00
|
|
|
else
|
2016-06-30 00:01:54 +00:00
|
|
|
MemMI = BuildMI(MF, MI.getDebugLoc(), get(MemOpc))
|
|
|
|
.addReg(MI.getOperand(1).getReg())
|
|
|
|
.addReg(BaseReg)
|
|
|
|
.addReg(0)
|
|
|
|
.addImm(0)
|
|
|
|
.addImm(Pred);
|
2009-07-08 16:09:28 +00:00
|
|
|
if (WB.isDead())
|
|
|
|
UpdateMI->getOperand(0).setIsDead();
|
|
|
|
NewMIs.push_back(UpdateMI);
|
|
|
|
NewMIs.push_back(MemMI);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Transfer LiveVariables states, kill / dead info.
|
|
|
|
if (LV) {
|
2016-06-30 00:01:54 +00:00
|
|
|
for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) {
|
|
|
|
MachineOperand &MO = MI.getOperand(i);
|
2019-08-01 23:27:28 +00:00
|
|
|
if (MO.isReg() && Register::isVirtualRegister(MO.getReg())) {
|
Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Partial reverts in:
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
X86FixupLEAs.cpp - Some functions return unsigned and arguably should be MCRegister
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
HexagonBitSimplify.cpp - Function takes BitTracker::RegisterRef which appears to be unsigned&
MachineVerifier.cpp - Ambiguous operator==() given MCRegister and const Register
PPCFastISel.cpp - No Register::operator-=()
PeepholeOptimizer.cpp - TargetInstrInfo::optimizeLoadInstr() takes an unsigned&
MachineTraceMetrics.cpp - MachineTraceMetrics lacks a suitable constructor
Manual fixups in:
ARMFastISel.cpp - ARMEmitLoad() now takes a Register& instead of unsigned&
HexagonSplitDouble.cpp - Ternary operator was ambiguous between unsigned/Register
HexagonConstExtenders.cpp - Has a local class named Register, used llvm::Register instead of Register.
PPCFastISel.cpp - PPCEmitLoad() now takes a Register& instead of unsigned&
Depends on D65919
Reviewers: arsenm, bogner, craig.topper, RKSimon
Reviewed By: arsenm
Subscribers: RKSimon, craig.topper, lenary, aemerson, wuzish, jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65962
llvm-svn: 369041
2019-08-15 19:22:08 +00:00
|
|
|
Register Reg = MO.getReg();
|
2009-07-08 16:09:28 +00:00
|
|
|
|
|
|
|
LiveVariables::VarInfo &VI = LV->getVarInfo(Reg);
|
|
|
|
if (MO.isDef()) {
|
|
|
|
MachineInstr *NewMI = (Reg == WBReg) ? UpdateMI : MemMI;
|
|
|
|
if (MO.isDead())
|
2016-07-01 01:51:32 +00:00
|
|
|
LV->addVirtualRegisterDead(Reg, *NewMI);
|
2009-07-08 16:09:28 +00:00
|
|
|
}
|
|
|
|
if (MO.isUse() && MO.isKill()) {
|
|
|
|
for (unsigned j = 0; j < 2; ++j) {
|
|
|
|
// Look at the two new MI's in reverse order.
|
|
|
|
MachineInstr *NewMI = NewMIs[j];
|
|
|
|
if (!NewMI->readsRegister(Reg))
|
|
|
|
continue;
|
2016-07-01 01:51:32 +00:00
|
|
|
LV->addVirtualRegisterKilled(Reg, *NewMI);
|
|
|
|
if (VI.removeKill(MI))
|
2009-07-08 16:09:28 +00:00
|
|
|
VI.Kills.push_back(NewMI);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
MachineBasicBlock::iterator MBBI = MI.getIterator();
|
2009-07-08 16:09:28 +00:00
|
|
|
MFI->insert(MBBI, NewMIs[1]);
|
|
|
|
MFI->insert(MBBI, NewMIs[0]);
|
|
|
|
return NewMIs[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
// Branch analysis.
|
2016-07-15 14:41:04 +00:00
|
|
|
bool ARMBaseInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
|
|
|
|
MachineBasicBlock *&TBB,
|
|
|
|
MachineBasicBlock *&FBB,
|
|
|
|
SmallVectorImpl<MachineOperand> &Cond,
|
|
|
|
bool AllowModify) const {
|
2014-04-25 05:30:21 +00:00
|
|
|
TBB = nullptr;
|
|
|
|
FBB = nullptr;
|
2013-07-19 23:52:47 +00:00
|
|
|
|
2009-07-08 16:09:28 +00:00
|
|
|
MachineBasicBlock::iterator I = MBB.end();
|
2010-04-02 01:38:09 +00:00
|
|
|
if (I == MBB.begin())
|
2013-07-19 23:52:47 +00:00
|
|
|
return false; // Empty blocks are easy.
|
2010-04-02 01:38:09 +00:00
|
|
|
--I;
|
2009-07-08 16:09:28 +00:00
|
|
|
|
2013-07-19 23:52:47 +00:00
|
|
|
// Walk backwards from the end of the basic block until the branch is
|
|
|
|
// analyzed or we give up.
|
2016-02-23 02:46:52 +00:00
|
|
|
while (isPredicated(*I) || I->isTerminator() || I->isDebugValue()) {
|
2013-07-19 23:52:47 +00:00
|
|
|
// Flag to be raised on unanalyzeable instructions. This is useful in cases
|
|
|
|
// where we want to clean up on the end of the basic block before we bail
|
|
|
|
// out.
|
|
|
|
bool CantAnalyze = false;
|
2013-05-05 18:06:32 +00:00
|
|
|
|
2013-07-19 23:52:47 +00:00
|
|
|
// Skip over DEBUG values and predicated nonterminators.
|
2018-05-09 02:42:00 +00:00
|
|
|
while (I->isDebugInstr() || !I->isTerminator()) {
|
2013-07-19 23:52:47 +00:00
|
|
|
if (I == MBB.begin())
|
|
|
|
return false;
|
|
|
|
--I;
|
2009-07-08 16:09:28 +00:00
|
|
|
}
|
2013-07-19 23:52:47 +00:00
|
|
|
|
|
|
|
if (isIndirectBranchOpcode(I->getOpcode()) ||
|
|
|
|
isJumpTableBranchOpcode(I->getOpcode())) {
|
|
|
|
// Indirect branches and jump tables can't be analyzed, but we still want
|
|
|
|
// to clean up any instructions at the tail of the basic block.
|
|
|
|
CantAnalyze = true;
|
|
|
|
} else if (isUncondBranchOpcode(I->getOpcode())) {
|
|
|
|
TBB = I->getOperand(0).getMBB();
|
|
|
|
} else if (isCondBranchOpcode(I->getOpcode())) {
|
|
|
|
// Bail out if we encounter multiple conditional branches.
|
|
|
|
if (!Cond.empty())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
assert(!FBB && "FBB should have been null.");
|
|
|
|
FBB = TBB;
|
|
|
|
TBB = I->getOperand(0).getMBB();
|
|
|
|
Cond.push_back(I->getOperand(1));
|
|
|
|
Cond.push_back(I->getOperand(2));
|
|
|
|
} else if (I->isReturn()) {
|
|
|
|
// Returns can't be analyzed, but we should run cleanup.
|
2016-02-23 02:46:52 +00:00
|
|
|
CantAnalyze = !isPredicated(*I);
|
2013-07-19 23:52:47 +00:00
|
|
|
} else {
|
|
|
|
// We encountered other unrecognized terminator. Bail out immediately.
|
|
|
|
return true;
|
2009-07-08 16:09:28 +00:00
|
|
|
}
|
|
|
|
|
2013-07-19 23:52:47 +00:00
|
|
|
// Cleanup code - to be run for unpredicated unconditional branches and
|
|
|
|
// returns.
|
2016-02-23 02:46:52 +00:00
|
|
|
if (!isPredicated(*I) &&
|
2013-07-19 23:52:47 +00:00
|
|
|
(isUncondBranchOpcode(I->getOpcode()) ||
|
|
|
|
isIndirectBranchOpcode(I->getOpcode()) ||
|
|
|
|
isJumpTableBranchOpcode(I->getOpcode()) ||
|
|
|
|
I->isReturn())) {
|
|
|
|
// Forget any previous condition branch information - it no longer applies.
|
|
|
|
Cond.clear();
|
2014-04-25 05:30:21 +00:00
|
|
|
FBB = nullptr;
|
2013-07-19 23:52:47 +00:00
|
|
|
|
|
|
|
// If we can modify the function, delete everything below this
|
|
|
|
// unconditional branch.
|
|
|
|
if (AllowModify) {
|
2014-03-02 12:27:27 +00:00
|
|
|
MachineBasicBlock::iterator DI = std::next(I);
|
2013-07-19 23:52:47 +00:00
|
|
|
while (DI != MBB.end()) {
|
2016-07-08 20:21:17 +00:00
|
|
|
MachineInstr &InstToDelete = *DI;
|
2013-07-19 23:52:47 +00:00
|
|
|
++DI;
|
2016-07-08 20:21:17 +00:00
|
|
|
InstToDelete.eraseFromParent();
|
2013-07-19 23:52:47 +00:00
|
|
|
}
|
2010-09-23 06:54:40 +00:00
|
|
|
}
|
|
|
|
}
|
2009-07-08 16:09:28 +00:00
|
|
|
|
2013-07-19 23:52:47 +00:00
|
|
|
if (CantAnalyze)
|
|
|
|
return true;
|
2009-07-08 16:09:28 +00:00
|
|
|
|
2013-07-19 23:52:47 +00:00
|
|
|
if (I == MBB.begin())
|
|
|
|
return false;
|
2009-07-08 16:09:28 +00:00
|
|
|
|
2013-07-19 23:52:47 +00:00
|
|
|
--I;
|
2009-07-08 16:09:28 +00:00
|
|
|
}
|
|
|
|
|
2013-07-19 23:52:47 +00:00
|
|
|
// We made it past the terminators without bailing out - we must have
|
|
|
|
// analyzed this branch successfully.
|
|
|
|
return false;
|
2009-07-08 16:09:28 +00:00
|
|
|
}
|
|
|
|
|
2016-09-14 20:43:16 +00:00
|
|
|
unsigned ARMBaseInstrInfo::removeBranch(MachineBasicBlock &MBB,
|
2016-09-14 17:23:48 +00:00
|
|
|
int *BytesRemoved) const {
|
|
|
|
assert(!BytesRemoved && "code size not handled");
|
|
|
|
|
2015-06-25 13:28:24 +00:00
|
|
|
MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();
|
|
|
|
if (I == MBB.end())
|
|
|
|
return 0;
|
|
|
|
|
2009-07-27 18:20:05 +00:00
|
|
|
if (!isUncondBranchOpcode(I->getOpcode()) &&
|
|
|
|
!isCondBranchOpcode(I->getOpcode()))
|
2009-07-08 16:09:28 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
// Remove the branch.
|
|
|
|
I->eraseFromParent();
|
|
|
|
|
|
|
|
I = MBB.end();
|
|
|
|
|
|
|
|
if (I == MBB.begin()) return 1;
|
|
|
|
--I;
|
2009-07-27 18:20:05 +00:00
|
|
|
if (!isCondBranchOpcode(I->getOpcode()))
|
2009-07-08 16:09:28 +00:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
// Remove the branch.
|
|
|
|
I->eraseFromParent();
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
2016-09-14 17:24:15 +00:00
|
|
|
unsigned ARMBaseInstrInfo::insertBranch(MachineBasicBlock &MBB,
|
2016-06-12 15:39:02 +00:00
|
|
|
MachineBasicBlock *TBB,
|
|
|
|
MachineBasicBlock *FBB,
|
|
|
|
ArrayRef<MachineOperand> Cond,
|
2016-09-14 17:23:48 +00:00
|
|
|
const DebugLoc &DL,
|
|
|
|
int *BytesAdded) const {
|
|
|
|
assert(!BytesAdded && "code size not handled");
|
2009-07-28 05:48:47 +00:00
|
|
|
ARMFunctionInfo *AFI = MBB.getParent()->getInfo<ARMFunctionInfo>();
|
|
|
|
int BOpc = !AFI->isThumbFunction()
|
|
|
|
? ARM::B : (AFI->isThumb2Function() ? ARM::t2B : ARM::tB);
|
|
|
|
int BccOpc = !AFI->isThumbFunction()
|
|
|
|
? ARM::Bcc : (AFI->isThumb2Function() ? ARM::t2Bcc : ARM::tBcc);
|
2011-09-09 21:48:23 +00:00
|
|
|
bool isThumb = AFI->isThumbFunction() || AFI->isThumb2Function();
|
2011-09-21 02:17:37 +00:00
|
|
|
|
2009-07-08 16:09:28 +00:00
|
|
|
// Shouldn't be a fall through.
|
2016-09-14 17:24:15 +00:00
|
|
|
assert(TBB && "insertBranch must not be told to insert a fallthrough");
|
2009-07-08 16:09:28 +00:00
|
|
|
assert((Cond.size() == 2 || Cond.size() == 0) &&
|
|
|
|
"ARM branch conditions have two components!");
|
|
|
|
|
2015-04-23 20:31:32 +00:00
|
|
|
// For conditional branches, we use addOperand to preserve CPSR flags.
|
|
|
|
|
2014-04-25 05:30:21 +00:00
|
|
|
if (!FBB) {
|
2011-09-09 23:13:02 +00:00
|
|
|
if (Cond.empty()) { // Unconditional branch?
|
2011-09-09 21:48:23 +00:00
|
|
|
if (isThumb)
|
2017-01-20 08:15:24 +00:00
|
|
|
BuildMI(&MBB, DL, get(BOpc)).addMBB(TBB).add(predOps(ARMCC::AL));
|
2011-09-09 21:48:23 +00:00
|
|
|
else
|
|
|
|
BuildMI(&MBB, DL, get(BOpc)).addMBB(TBB);
|
2011-09-09 23:13:02 +00:00
|
|
|
} else
|
2017-01-13 09:58:52 +00:00
|
|
|
BuildMI(&MBB, DL, get(BccOpc))
|
|
|
|
.addMBB(TBB)
|
|
|
|
.addImm(Cond[0].getImm())
|
|
|
|
.add(Cond[1]);
|
2009-07-08 16:09:28 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Two-way conditional branch.
|
2017-01-13 09:58:52 +00:00
|
|
|
BuildMI(&MBB, DL, get(BccOpc))
|
|
|
|
.addMBB(TBB)
|
|
|
|
.addImm(Cond[0].getImm())
|
|
|
|
.add(Cond[1]);
|
2011-09-09 21:48:23 +00:00
|
|
|
if (isThumb)
|
2017-01-20 08:15:24 +00:00
|
|
|
BuildMI(&MBB, DL, get(BOpc)).addMBB(FBB).add(predOps(ARMCC::AL));
|
2011-09-09 21:48:23 +00:00
|
|
|
else
|
|
|
|
BuildMI(&MBB, DL, get(BOpc)).addMBB(FBB);
|
2009-07-08 16:09:28 +00:00
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ARMBaseInstrInfo::
|
2016-09-14 20:43:16 +00:00
|
|
|
reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const {
|
2009-07-08 16:09:28 +00:00
|
|
|
ARMCC::CondCodes CC = (ARMCC::CondCodes)(int)Cond[0].getImm();
|
|
|
|
Cond[0].setImm(ARMCC::getOppositeCondition(CC));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-02-23 02:46:52 +00:00
|
|
|
bool ARMBaseInstrInfo::isPredicated(const MachineInstr &MI) const {
|
|
|
|
if (MI.isBundle()) {
|
|
|
|
MachineBasicBlock::const_instr_iterator I = MI.getIterator();
|
|
|
|
MachineBasicBlock::const_instr_iterator E = MI.getParent()->instr_end();
|
2011-12-14 02:11:42 +00:00
|
|
|
while (++I != E && I->isInsideBundle()) {
|
|
|
|
int PIdx = I->findFirstPredOperandIdx();
|
|
|
|
if (PIdx != -1 && I->getOperand(PIdx).getImm() != ARMCC::AL)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-02-23 02:46:52 +00:00
|
|
|
int PIdx = MI.findFirstPredOperandIdx();
|
|
|
|
return PIdx != -1 && MI.getOperand(PIdx).getImm() != ARMCC::AL;
|
2011-12-14 02:11:42 +00:00
|
|
|
}
|
|
|
|
|
[MIR] Add comments to INLINEASM immediate flag MachineOperands
Summary:
The INLINEASM MIR instructions use immediate operands to encode the values of some operands.
The MachineInstr pretty printer function already handles those operands and prints human readable annotations instead of the immediates. This patch adds similar annotations to the output of the MIRPrinter, however uses the new MIROperandComment feature.
Reviewers: SjoerdMeijer, arsenm, efriedma
Reviewed By: arsenm
Subscribers: qcolombet, sdardis, jvesely, wdng, nhaehnle, hiraditya, jrtc27, atanasyan, kerbowa, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D78088
2020-04-14 09:24:40 +02:00
|
|
|
std::string ARMBaseInstrInfo::createMIROperandComment(
|
|
|
|
const MachineInstr &MI, const MachineOperand &Op, unsigned OpIdx,
|
|
|
|
const TargetRegisterInfo *TRI) const {
|
|
|
|
|
|
|
|
// First, let's see if there is a generic comment for this operand
|
|
|
|
std::string GenericComment =
|
|
|
|
TargetInstrInfo::createMIROperandComment(MI, Op, OpIdx, TRI);
|
|
|
|
if (!GenericComment.empty())
|
|
|
|
return GenericComment;
|
|
|
|
|
|
|
|
// If not, check if we have an immediate operand.
|
[MIR][ARM] MachineOperand comments
This adds infrastructure to print and parse MIR MachineOperand comments.
The motivation for the ARM backend is to print condition code names instead of
magic constants that are difficult to read (for human beings). For example,
instead of this:
dead renamable $r2, $cpsr = tEOR killed renamable $r2, renamable $r1, 14, $noreg
t2Bcc %bb.4, 0, killed $cpsr
we now print this:
dead renamable $r2, $cpsr = tEOR killed renamable $r2, renamable $r1, 14 /* CC::always */, $noreg
t2Bcc %bb.4, 0 /* CC:eq */, killed $cpsr
This shows that MachineOperand comments are enclosed between /* and */. In this
example, the EOR instruction is not conditionally executed (i.e. it is "always
executed"), which is encoded by the 14 immediate machine operand. Thus, now
this machine operand has /* CC::always */ as a comment. The 0 on the next
conditional branch instruction represents the equal condition code, thus now
this operand has /* CC:eq */ as a comment.
As it is a comment, the MI lexer/parser completely ignores it. The benefit is
that this keeps the change in the lexer extremely minimal and no target
specific parsing needs to be done. The changes on the MIPrinter side are also
minimal, as there is only one target hooks that is used to create the machine
operand comments.
Differential Revision: https://reviews.llvm.org/D74306
2020-02-24 14:19:21 +00:00
|
|
|
if (Op.getType() != MachineOperand::MO_Immediate)
|
|
|
|
return std::string();
|
|
|
|
|
|
|
|
// And print its corresponding condition code if the immediate is a
|
|
|
|
// predicate.
|
|
|
|
int FirstPredOp = MI.findFirstPredOperandIdx();
|
|
|
|
if (FirstPredOp != (int) OpIdx)
|
|
|
|
return std::string();
|
|
|
|
|
|
|
|
std::string CC = "CC::";
|
|
|
|
CC += ARMCondCodeToString((ARMCC::CondCodes)Op.getImm());
|
|
|
|
return CC;
|
|
|
|
}
|
|
|
|
|
2016-02-23 02:46:52 +00:00
|
|
|
bool ARMBaseInstrInfo::PredicateInstruction(
|
|
|
|
MachineInstr &MI, ArrayRef<MachineOperand> Pred) const {
|
|
|
|
unsigned Opc = MI.getOpcode();
|
2009-07-27 18:20:05 +00:00
|
|
|
if (isUncondBranchOpcode(Opc)) {
|
2016-02-23 02:46:52 +00:00
|
|
|
MI.setDesc(get(getMatchingCondBranchOpcode(Opc)));
|
|
|
|
MachineInstrBuilder(*MI.getParent()->getParent(), MI)
|
2012-12-20 22:53:55 +00:00
|
|
|
.addImm(Pred[0].getImm())
|
|
|
|
.addReg(Pred[1].getReg());
|
2009-07-08 16:09:28 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-02-23 02:46:52 +00:00
|
|
|
int PIdx = MI.findFirstPredOperandIdx();
|
2009-07-08 16:09:28 +00:00
|
|
|
if (PIdx != -1) {
|
2016-02-23 02:46:52 +00:00
|
|
|
MachineOperand &PMO = MI.getOperand(PIdx);
|
2009-07-08 16:09:28 +00:00
|
|
|
PMO.setImm(Pred[0].getImm());
|
2016-02-23 02:46:52 +00:00
|
|
|
MI.getOperand(PIdx+1).setReg(Pred[1].getReg());
|
2009-07-08 16:09:28 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-06-11 19:30:37 +00:00
|
|
|
bool ARMBaseInstrInfo::SubsumesPredicate(ArrayRef<MachineOperand> Pred1,
|
|
|
|
ArrayRef<MachineOperand> Pred2) const {
|
2009-07-08 16:09:28 +00:00
|
|
|
if (Pred1.size() > 2 || Pred2.size() > 2)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
ARMCC::CondCodes CC1 = (ARMCC::CondCodes)Pred1[0].getImm();
|
|
|
|
ARMCC::CondCodes CC2 = (ARMCC::CondCodes)Pred2[0].getImm();
|
|
|
|
if (CC1 == CC2)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
switch (CC1) {
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
case ARMCC::AL:
|
|
|
|
return true;
|
|
|
|
case ARMCC::HS:
|
|
|
|
return CC2 == ARMCC::HI;
|
|
|
|
case ARMCC::LS:
|
|
|
|
return CC2 == ARMCC::LO || CC2 == ARMCC::EQ;
|
|
|
|
case ARMCC::GE:
|
|
|
|
return CC2 == ARMCC::GT;
|
|
|
|
case ARMCC::LE:
|
|
|
|
return CC2 == ARMCC::LT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-23 02:46:52 +00:00
|
|
|
bool ARMBaseInstrInfo::DefinesPredicate(
|
|
|
|
MachineInstr &MI, std::vector<MachineOperand> &Pred) const {
|
2009-07-08 16:09:28 +00:00
|
|
|
bool Found = false;
|
2016-02-23 02:46:52 +00:00
|
|
|
for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) {
|
|
|
|
const MachineOperand &MO = MI.getOperand(i);
|
2012-02-17 19:23:15 +00:00
|
|
|
if ((MO.isRegMask() && MO.clobbersPhysReg(ARM::CPSR)) ||
|
|
|
|
(MO.isReg() && MO.isDef() && MO.getReg() == ARM::CPSR)) {
|
2009-07-08 16:09:28 +00:00
|
|
|
Pred.push_back(MO);
|
|
|
|
Found = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Found;
|
|
|
|
}
|
|
|
|
|
2017-06-02 08:53:19 +00:00
|
|
|
bool ARMBaseInstrInfo::isCPSRDefined(const MachineInstr &MI) {
|
|
|
|
for (const auto &MO : MI.operands())
|
2015-08-03 09:24:48 +00:00
|
|
|
if (MO.isReg() && MO.getReg() == ARM::CPSR && MO.isDef() && !MO.isDead())
|
2014-08-10 22:20:37 +00:00
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-06-02 08:53:19 +00:00
|
|
|
bool ARMBaseInstrInfo::isAddrMode3OpImm(const MachineInstr &MI,
|
|
|
|
unsigned Op) const {
|
|
|
|
const MachineOperand &Offset = MI.getOperand(Op + 1);
|
|
|
|
return Offset.getReg() != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Load with negative register offset requires additional 1cyc and +I unit
|
|
|
|
// for Cortex A57
|
|
|
|
bool ARMBaseInstrInfo::isAddrMode3OpMinusReg(const MachineInstr &MI,
|
|
|
|
unsigned Op) const {
|
|
|
|
const MachineOperand &Offset = MI.getOperand(Op + 1);
|
|
|
|
const MachineOperand &Opc = MI.getOperand(Op + 2);
|
|
|
|
assert(Opc.isImm());
|
|
|
|
assert(Offset.isReg());
|
|
|
|
int64_t OpcImm = Opc.getImm();
|
|
|
|
|
|
|
|
bool isSub = ARM_AM::getAM3Op(OpcImm) == ARM_AM::sub;
|
|
|
|
return (isSub && Offset.getReg() != 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ARMBaseInstrInfo::isLdstScaledReg(const MachineInstr &MI,
|
|
|
|
unsigned Op) const {
|
|
|
|
const MachineOperand &Opc = MI.getOperand(Op + 2);
|
|
|
|
unsigned OffImm = Opc.getImm();
|
|
|
|
return ARM_AM::getAM2ShiftOpc(OffImm) != ARM_AM::no_shift;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Load, scaled register offset, not plus LSL2
|
|
|
|
bool ARMBaseInstrInfo::isLdstScaledRegNotPlusLsl2(const MachineInstr &MI,
|
|
|
|
unsigned Op) const {
|
|
|
|
const MachineOperand &Opc = MI.getOperand(Op + 2);
|
|
|
|
unsigned OffImm = Opc.getImm();
|
|
|
|
|
|
|
|
bool isAdd = ARM_AM::getAM2Op(OffImm) == ARM_AM::add;
|
|
|
|
unsigned Amt = ARM_AM::getAM2Offset(OffImm);
|
|
|
|
ARM_AM::ShiftOpc ShiftOpc = ARM_AM::getAM2ShiftOpc(OffImm);
|
|
|
|
if (ShiftOpc == ARM_AM::no_shift) return false; // not scaled
|
|
|
|
bool SimpleScaled = (isAdd && ShiftOpc == ARM_AM::lsl && Amt == 2);
|
|
|
|
return !SimpleScaled;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Minus reg for ldstso addr mode
|
|
|
|
bool ARMBaseInstrInfo::isLdstSoMinusReg(const MachineInstr &MI,
|
|
|
|
unsigned Op) const {
|
|
|
|
unsigned OffImm = MI.getOperand(Op + 2).getImm();
|
|
|
|
return ARM_AM::getAM2Op(OffImm) == ARM_AM::sub;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Load, scaled register offset
|
|
|
|
bool ARMBaseInstrInfo::isAm2ScaledReg(const MachineInstr &MI,
|
|
|
|
unsigned Op) const {
|
|
|
|
unsigned OffImm = MI.getOperand(Op + 2).getImm();
|
|
|
|
return ARM_AM::getAM2ShiftOpc(OffImm) != ARM_AM::no_shift;
|
|
|
|
}
|
|
|
|
|
2014-08-11 20:13:25 +00:00
|
|
|
static bool isEligibleForITBlock(const MachineInstr *MI) {
|
|
|
|
switch (MI->getOpcode()) {
|
|
|
|
default: return true;
|
|
|
|
case ARM::tADC: // ADC (register) T1
|
|
|
|
case ARM::tADDi3: // ADD (immediate) T1
|
|
|
|
case ARM::tADDi8: // ADD (immediate) T2
|
|
|
|
case ARM::tADDrr: // ADD (register) T1
|
|
|
|
case ARM::tAND: // AND (register) T1
|
|
|
|
case ARM::tASRri: // ASR (immediate) T1
|
|
|
|
case ARM::tASRrr: // ASR (register) T1
|
|
|
|
case ARM::tBIC: // BIC (register) T1
|
|
|
|
case ARM::tEOR: // EOR (register) T1
|
|
|
|
case ARM::tLSLri: // LSL (immediate) T1
|
|
|
|
case ARM::tLSLrr: // LSL (register) T1
|
|
|
|
case ARM::tLSRri: // LSR (immediate) T1
|
|
|
|
case ARM::tLSRrr: // LSR (register) T1
|
|
|
|
case ARM::tMUL: // MUL T1
|
|
|
|
case ARM::tMVN: // MVN (register) T1
|
|
|
|
case ARM::tORR: // ORR (register) T1
|
|
|
|
case ARM::tROR: // ROR (register) T1
|
|
|
|
case ARM::tRSB: // RSB (immediate) T1
|
|
|
|
case ARM::tSBC: // SBC (register) T1
|
|
|
|
case ARM::tSUBi3: // SUB (immediate) T1
|
|
|
|
case ARM::tSUBi8: // SUB (immediate) T2
|
|
|
|
case ARM::tSUBrr: // SUB (register) T1
|
2017-06-02 08:53:19 +00:00
|
|
|
return !ARMBaseInstrInfo::isCPSRDefined(*MI);
|
2014-08-11 20:13:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-21 06:21:52 +00:00
|
|
|
/// isPredicable - Return true if the specified instruction can be predicated.
|
|
|
|
/// By default, this returns true for every instruction with a
|
|
|
|
/// PredicateOperand.
|
2017-03-03 18:30:54 +00:00
|
|
|
bool ARMBaseInstrInfo::isPredicable(const MachineInstr &MI) const {
|
2016-02-23 02:46:52 +00:00
|
|
|
if (!MI.isPredicable())
|
2009-11-21 06:21:52 +00:00
|
|
|
return false;
|
|
|
|
|
ARM: workaround bundled operation predication
This is a Windows ARM specific issue. If the code path in the if conversion
ends up using a relocation which will form a IMAGE_REL_ARM_MOV32T, we end up
with a bundle to ensure that the mov.w/mov.t pair is not split up. This is
normally fine, however, if the branch is also predicated, then we end up trying
to predicate the bundle.
For now, report a bundle as being unpredicatable. Although this is false, this
would trigger a failure case previously anyways, so this is no worse. That is,
there should not be any code which would previously have been if converted and
predicated which would not be now.
Under certain circumstances, it may be possible to "predicate the bundle". This
would require scanning all bundle instructions, and ensure that the bundle
contains only predicatable instructions, and converting the bundle into an IT
block sequence. If the bundle is larger than the maximal IT block length (4
instructions), it would require materializing multiple IT blocks from the single
bundle.
llvm-svn: 280689
2016-09-06 04:00:12 +00:00
|
|
|
if (MI.isBundle())
|
|
|
|
return false;
|
|
|
|
|
2016-02-23 02:46:52 +00:00
|
|
|
if (!isEligibleForITBlock(&MI))
|
2014-08-11 20:13:25 +00:00
|
|
|
return false;
|
2014-08-10 22:20:37 +00:00
|
|
|
|
2017-03-03 18:30:54 +00:00
|
|
|
const ARMFunctionInfo *AFI =
|
2016-02-23 02:46:52 +00:00
|
|
|
MI.getParent()->getParent()->getInfo<ARMFunctionInfo>();
|
2013-09-09 14:21:49 +00:00
|
|
|
|
2017-06-22 12:11:38 +00:00
|
|
|
// Neon instructions in Thumb2 IT blocks are deprecated, see ARMARM.
|
|
|
|
// In their ARM encoding, they can't be encoded in a conditional form.
|
|
|
|
if ((MI.getDesc().TSFlags & ARMII::DomainMask) == ARMII::DomainNEON)
|
|
|
|
return false;
|
|
|
|
|
2013-09-09 14:21:49 +00:00
|
|
|
if (AFI->isThumb2Function()) {
|
2013-11-13 18:29:49 +00:00
|
|
|
if (getSubtarget().restrictIT())
|
2016-02-23 02:46:52 +00:00
|
|
|
return isV8EligibleForIT(&MI);
|
2009-11-21 06:21:52 +00:00
|
|
|
}
|
2013-09-09 14:21:49 +00:00
|
|
|
|
2009-11-21 06:21:52 +00:00
|
|
|
return true;
|
|
|
|
}
|
2009-07-08 16:09:28 +00:00
|
|
|
|
2014-04-12 18:45:24 +00:00
|
|
|
namespace llvm {
|
2017-01-26 23:40:06 +00:00
|
|
|
|
2017-03-03 18:30:54 +00:00
|
|
|
template <> bool IsCPSRDead<MachineInstr>(const MachineInstr *MI) {
|
2014-02-26 11:27:28 +00:00
|
|
|
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
|
|
|
|
const MachineOperand &MO = MI->getOperand(i);
|
|
|
|
if (!MO.isReg() || MO.isUndef() || MO.isUse())
|
|
|
|
continue;
|
|
|
|
if (MO.getReg() != ARM::CPSR)
|
|
|
|
continue;
|
|
|
|
if (!MO.isDead())
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// all definitions of CPSR are dead
|
|
|
|
return true;
|
|
|
|
}
|
2017-01-26 23:40:06 +00:00
|
|
|
|
|
|
|
} // end namespace llvm
|
2014-02-26 11:27:28 +00:00
|
|
|
|
2009-07-08 16:09:28 +00:00
|
|
|
/// GetInstSize - Return the size of the specified MachineInstr.
|
|
|
|
///
|
2016-07-28 16:32:22 +00:00
|
|
|
unsigned ARMBaseInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
|
2016-06-30 00:01:54 +00:00
|
|
|
const MachineBasicBlock &MBB = *MI.getParent();
|
2009-07-08 16:09:28 +00:00
|
|
|
const MachineFunction *MF = MBB.getParent();
|
2009-08-22 21:43:10 +00:00
|
|
|
const MCAsmInfo *MAI = MF->getTarget().getMCAsmInfo();
|
2009-07-08 16:09:28 +00:00
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
const MCInstrDesc &MCID = MI.getDesc();
|
2011-07-13 23:22:26 +00:00
|
|
|
if (MCID.getSize())
|
|
|
|
return MCID.getSize();
|
2009-07-08 16:09:28 +00:00
|
|
|
|
[ARM] additionally check for ARM::INLINEASM_BR w/ ARM::INLINEASM
Summary:
We were observing failures for arm32 allyesconfigs of the Linux kernel
with the asm goto Clang patch, where ldr's were being generated to
offsets too far away to encode in imm12.
It looks like since INLINEASM_BR was created off of INLINEASM, a few
checks for INLINEASM needed to be updated to check for either case.
pr/41999
Link: https://github.com/ClangBuiltLinux/linux/issues/490
Reviewers: peter.smith, kristof.beyls, ostannard, rengolin, t.p.northover
Reviewed By: peter.smith
Subscribers: jyu2, javed.absar, hiraditya, llvm-commits, nathanchance, craig.topper, kees, srhines
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D62400
llvm-svn: 361659
2019-05-24 18:58:21 +00:00
|
|
|
switch (MI.getOpcode()) {
|
2014-03-07 04:45:03 +00:00
|
|
|
default:
|
|
|
|
// pseudo-instruction sizes are zero.
|
2012-01-20 21:51:11 +00:00
|
|
|
return 0;
|
|
|
|
case TargetOpcode::BUNDLE:
|
|
|
|
return getInstBundleLength(MI);
|
|
|
|
case ARM::MOVi16_ga_pcrel:
|
|
|
|
case ARM::MOVTi16_ga_pcrel:
|
|
|
|
case ARM::t2MOVi16_ga_pcrel:
|
|
|
|
case ARM::t2MOVTi16_ga_pcrel:
|
|
|
|
return 4;
|
|
|
|
case ARM::MOVi32imm:
|
|
|
|
case ARM::t2MOVi32imm:
|
|
|
|
return 8;
|
|
|
|
case ARM::CONSTPOOL_ENTRY:
|
2015-05-31 19:22:07 +00:00
|
|
|
case ARM::JUMPTABLE_INSTS:
|
|
|
|
case ARM::JUMPTABLE_ADDRS:
|
|
|
|
case ARM::JUMPTABLE_TBB:
|
|
|
|
case ARM::JUMPTABLE_TBH:
|
2012-01-20 21:51:11 +00:00
|
|
|
// If this machine instr is a constant pool entry, its size is recorded as
|
|
|
|
// operand #2.
|
2016-06-30 00:01:54 +00:00
|
|
|
return MI.getOperand(2).getImm();
|
2012-01-20 21:51:11 +00:00
|
|
|
case ARM::Int_eh_sjlj_longjmp:
|
|
|
|
return 16;
|
|
|
|
case ARM::tInt_eh_sjlj_longjmp:
|
|
|
|
return 10;
|
2016-07-08 00:48:22 +00:00
|
|
|
case ARM::tInt_WIN_eh_sjlj_longjmp:
|
|
|
|
return 12;
|
2012-01-20 21:51:11 +00:00
|
|
|
case ARM::Int_eh_sjlj_setjmp:
|
|
|
|
case ARM::Int_eh_sjlj_setjmp_nofp:
|
|
|
|
return 20;
|
|
|
|
case ARM::tInt_eh_sjlj_setjmp:
|
|
|
|
case ARM::t2Int_eh_sjlj_setjmp:
|
|
|
|
case ARM::t2Int_eh_sjlj_setjmp_nofp:
|
|
|
|
return 12;
|
2014-11-13 17:58:48 +00:00
|
|
|
case ARM::SPACE:
|
2016-06-30 00:01:54 +00:00
|
|
|
return MI.getOperand(1).getImm();
|
[ARM] additionally check for ARM::INLINEASM_BR w/ ARM::INLINEASM
Summary:
We were observing failures for arm32 allyesconfigs of the Linux kernel
with the asm goto Clang patch, where ldr's were being generated to
offsets too far away to encode in imm12.
It looks like since INLINEASM_BR was created off of INLINEASM, a few
checks for INLINEASM needed to be updated to check for either case.
pr/41999
Link: https://github.com/ClangBuiltLinux/linux/issues/490
Reviewers: peter.smith, kristof.beyls, ostannard, rengolin, t.p.northover
Reviewed By: peter.smith
Subscribers: jyu2, javed.absar, hiraditya, llvm-commits, nathanchance, craig.topper, kees, srhines
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D62400
llvm-svn: 361659
2019-05-24 18:58:21 +00:00
|
|
|
case ARM::INLINEASM:
|
|
|
|
case ARM::INLINEASM_BR: {
|
|
|
|
// If this machine instr is an inline asm, measure it.
|
|
|
|
unsigned Size = getInlineAsmLength(MI.getOperand(0).getSymbolName(), *MAI);
|
|
|
|
if (!MF->getInfo<ARMFunctionInfo>()->isThumbFunction())
|
|
|
|
Size = alignTo(Size, 4);
|
|
|
|
return Size;
|
|
|
|
}
|
2012-01-20 21:51:11 +00:00
|
|
|
}
|
2009-07-08 16:09:28 +00:00
|
|
|
}
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
unsigned ARMBaseInstrInfo::getInstBundleLength(const MachineInstr &MI) const {
|
2011-12-14 02:11:42 +00:00
|
|
|
unsigned Size = 0;
|
2016-06-30 00:01:54 +00:00
|
|
|
MachineBasicBlock::const_instr_iterator I = MI.getIterator();
|
|
|
|
MachineBasicBlock::const_instr_iterator E = MI.getParent()->instr_end();
|
2011-12-14 02:11:42 +00:00
|
|
|
while (++I != E && I->isInsideBundle()) {
|
|
|
|
assert(!I->isBundle() && "No nested bundle!");
|
2016-07-28 16:32:22 +00:00
|
|
|
Size += getInstSizeInBytes(*I);
|
2011-12-14 02:11:42 +00:00
|
|
|
}
|
|
|
|
return Size;
|
|
|
|
}
|
|
|
|
|
2014-10-01 19:21:03 +00:00
|
|
|
void ARMBaseInstrInfo::copyFromCPSR(MachineBasicBlock &MBB,
|
|
|
|
MachineBasicBlock::iterator I,
|
|
|
|
unsigned DestReg, bool KillSrc,
|
|
|
|
const ARMSubtarget &Subtarget) const {
|
|
|
|
unsigned Opc = Subtarget.isThumb()
|
|
|
|
? (Subtarget.isMClass() ? ARM::t2MRS_M : ARM::t2MRS_AR)
|
|
|
|
: ARM::MRS;
|
|
|
|
|
|
|
|
MachineInstrBuilder MIB =
|
|
|
|
BuildMI(MBB, I, I->getDebugLoc(), get(Opc), DestReg);
|
|
|
|
|
|
|
|
// There is only 1 A/R class MRS instruction, and it always refers to
|
|
|
|
// APSR. However, there are lots of other possibilities on M-class cores.
|
|
|
|
if (Subtarget.isMClass())
|
|
|
|
MIB.addImm(0x800);
|
|
|
|
|
2017-01-13 09:37:56 +00:00
|
|
|
MIB.add(predOps(ARMCC::AL))
|
|
|
|
.addReg(ARM::CPSR, RegState::Implicit | getKillRegState(KillSrc));
|
2014-10-01 19:21:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ARMBaseInstrInfo::copyToCPSR(MachineBasicBlock &MBB,
|
|
|
|
MachineBasicBlock::iterator I,
|
|
|
|
unsigned SrcReg, bool KillSrc,
|
|
|
|
const ARMSubtarget &Subtarget) const {
|
|
|
|
unsigned Opc = Subtarget.isThumb()
|
|
|
|
? (Subtarget.isMClass() ? ARM::t2MSR_M : ARM::t2MSR_AR)
|
|
|
|
: ARM::MSR;
|
|
|
|
|
|
|
|
MachineInstrBuilder MIB = BuildMI(MBB, I, I->getDebugLoc(), get(Opc));
|
|
|
|
|
|
|
|
if (Subtarget.isMClass())
|
|
|
|
MIB.addImm(0x800);
|
|
|
|
else
|
|
|
|
MIB.addImm(8);
|
|
|
|
|
2017-01-13 09:37:56 +00:00
|
|
|
MIB.addReg(SrcReg, getKillRegState(KillSrc))
|
|
|
|
.add(predOps(ARMCC::AL))
|
|
|
|
.addReg(ARM::CPSR, RegState::Implicit | RegState::Define);
|
2014-10-01 19:21:03 +00:00
|
|
|
}
|
|
|
|
|
[ARM] Code-generation infrastructure for MVE.
This provides the low-level support to start using MVE vector types in
LLVM IR, loading and storing them, passing them to __asm__ statements
containing hand-written MVE vector instructions, and *if* you have the
hard-float ABI turned on, using them as function parameters.
(In the soft-float ABI, vector types are passed in integer registers,
and combining all those 32-bit integers into a q-reg requires support
for selection DAG nodes like insert_vector_elt and build_vector which
aren't implemented yet for MVE. In fact I've also had to add
`arm_aapcs_vfpcc` to a couple of existing tests to avoid that
problem.)
Specifically, this commit adds support for:
* spills, reloads and register moves for MVE vector registers
* ditto for the VPT predication mask that lives in VPR.P0
* make all the MVE vector types legal in ISel, and provide selection
DAG patterns for BITCAST, LOAD and STORE
* make loads and stores of scalar FP types conditional on
`hasFPRegs()` rather than `hasVFP2Base()`. As a result a few
existing tests needed their llc command lines updating to use
`-mattr=-fpregs` as their method of turning off all hardware FP
support.
Reviewers: dmgreen, samparker, SjoerdMeijer
Subscribers: javed.absar, kristof.beyls, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60708
llvm-svn: 364329
2019-06-25 16:48:46 +00:00
|
|
|
void llvm::addUnpredicatedMveVpredNOp(MachineInstrBuilder &MIB) {
|
|
|
|
MIB.addImm(ARMVCC::None);
|
|
|
|
MIB.addReg(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void llvm::addUnpredicatedMveVpredROp(MachineInstrBuilder &MIB,
|
2020-04-07 17:28:53 -04:00
|
|
|
Register DestReg) {
|
[ARM] Code-generation infrastructure for MVE.
This provides the low-level support to start using MVE vector types in
LLVM IR, loading and storing them, passing them to __asm__ statements
containing hand-written MVE vector instructions, and *if* you have the
hard-float ABI turned on, using them as function parameters.
(In the soft-float ABI, vector types are passed in integer registers,
and combining all those 32-bit integers into a q-reg requires support
for selection DAG nodes like insert_vector_elt and build_vector which
aren't implemented yet for MVE. In fact I've also had to add
`arm_aapcs_vfpcc` to a couple of existing tests to avoid that
problem.)
Specifically, this commit adds support for:
* spills, reloads and register moves for MVE vector registers
* ditto for the VPT predication mask that lives in VPR.P0
* make all the MVE vector types legal in ISel, and provide selection
DAG patterns for BITCAST, LOAD and STORE
* make loads and stores of scalar FP types conditional on
`hasFPRegs()` rather than `hasVFP2Base()`. As a result a few
existing tests needed their llc command lines updating to use
`-mattr=-fpregs` as their method of turning off all hardware FP
support.
Reviewers: dmgreen, samparker, SjoerdMeijer
Subscribers: javed.absar, kristof.beyls, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60708
llvm-svn: 364329
2019-06-25 16:48:46 +00:00
|
|
|
addUnpredicatedMveVpredNOp(MIB);
|
|
|
|
MIB.addReg(DestReg, RegState::Undef);
|
|
|
|
}
|
|
|
|
|
|
|
|
void llvm::addPredicatedMveVpredNOp(MachineInstrBuilder &MIB, unsigned Cond) {
|
|
|
|
MIB.addImm(Cond);
|
|
|
|
MIB.addReg(ARM::VPR, RegState::Implicit);
|
|
|
|
}
|
|
|
|
|
|
|
|
void llvm::addPredicatedMveVpredROp(MachineInstrBuilder &MIB,
|
|
|
|
unsigned Cond, unsigned Inactive) {
|
|
|
|
addPredicatedMveVpredNOp(MIB, Cond);
|
|
|
|
MIB.addReg(Inactive);
|
|
|
|
}
|
|
|
|
|
2010-07-11 06:33:54 +00:00
|
|
|
void ARMBaseInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
|
2016-06-12 15:39:02 +00:00
|
|
|
MachineBasicBlock::iterator I,
|
2019-11-11 13:54:21 +05:30
|
|
|
const DebugLoc &DL, MCRegister DestReg,
|
|
|
|
MCRegister SrcReg, bool KillSrc) const {
|
2010-07-11 06:33:54 +00:00
|
|
|
bool GPRDest = ARM::GPRRegClass.contains(DestReg);
|
2013-10-22 02:29:35 +00:00
|
|
|
bool GPRSrc = ARM::GPRRegClass.contains(SrcReg);
|
2010-07-11 06:33:54 +00:00
|
|
|
|
|
|
|
if (GPRDest && GPRSrc) {
|
2017-01-13 10:18:01 +00:00
|
|
|
BuildMI(MBB, I, DL, get(ARM::MOVr), DestReg)
|
|
|
|
.addReg(SrcReg, getKillRegState(KillSrc))
|
|
|
|
.add(predOps(ARMCC::AL))
|
|
|
|
.add(condCodeOp());
|
2010-07-11 06:33:54 +00:00
|
|
|
return;
|
2009-08-05 21:02:22 +00:00
|
|
|
}
|
2009-07-08 16:09:28 +00:00
|
|
|
|
2010-07-11 06:33:54 +00:00
|
|
|
bool SPRDest = ARM::SPRRegClass.contains(DestReg);
|
2013-10-22 02:29:35 +00:00
|
|
|
bool SPRSrc = ARM::SPRRegClass.contains(SrcReg);
|
2010-07-11 06:33:54 +00:00
|
|
|
|
2011-08-20 00:17:25 +00:00
|
|
|
unsigned Opc = 0;
|
2011-10-11 00:59:06 +00:00
|
|
|
if (SPRDest && SPRSrc)
|
2010-07-11 06:33:54 +00:00
|
|
|
Opc = ARM::VMOVS;
|
2011-10-11 00:59:06 +00:00
|
|
|
else if (GPRDest && SPRSrc)
|
2010-07-11 06:33:54 +00:00
|
|
|
Opc = ARM::VMOVRS;
|
|
|
|
else if (SPRDest && GPRSrc)
|
|
|
|
Opc = ARM::VMOVSR;
|
[ARM] Replace fp-only-sp and d16 with fp64 and d32.
Those two subtarget features were awkward because their semantics are
reversed: each one indicates the _lack_ of support for something in
the architecture, rather than the presence. As a consequence, you
don't get the behavior you want if you combine two sets of feature
bits.
Each SubtargetFeature for an FP architecture version now comes in four
versions, one for each combination of those options. So you can still
say (for example) '+vfp2' in a feature string and it will mean what
it's always meant, but there's a new string '+vfp2d16sp' meaning the
version without those extra options.
A lot of this change is just mechanically replacing positive checks
for the old features with negative checks for the new ones. But one
more interesting change is that I've rearranged getFPUFeatures() so
that the main FPU feature is appended to the output list *before*
rather than after the features derived from the Restriction field, so
that -fp64 and -d32 can override defaults added by the main feature.
Reviewers: dmgreen, samparker, SjoerdMeijer
Subscribers: srhines, javed.absar, eraman, kristof.beyls, hiraditya, zzheng, Petar.Avramovic, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D60691
llvm-svn: 361845
2019-05-28 16:13:20 +00:00
|
|
|
else if (ARM::DPRRegClass.contains(DestReg, SrcReg) && Subtarget.hasFP64())
|
2010-07-11 06:33:54 +00:00
|
|
|
Opc = ARM::VMOVD;
|
|
|
|
else if (ARM::QPRRegClass.contains(DestReg, SrcReg))
|
[ARM] Code-generation infrastructure for MVE.
This provides the low-level support to start using MVE vector types in
LLVM IR, loading and storing them, passing them to __asm__ statements
containing hand-written MVE vector instructions, and *if* you have the
hard-float ABI turned on, using them as function parameters.
(In the soft-float ABI, vector types are passed in integer registers,
and combining all those 32-bit integers into a q-reg requires support
for selection DAG nodes like insert_vector_elt and build_vector which
aren't implemented yet for MVE. In fact I've also had to add
`arm_aapcs_vfpcc` to a couple of existing tests to avoid that
problem.)
Specifically, this commit adds support for:
* spills, reloads and register moves for MVE vector registers
* ditto for the VPT predication mask that lives in VPR.P0
* make all the MVE vector types legal in ISel, and provide selection
DAG patterns for BITCAST, LOAD and STORE
* make loads and stores of scalar FP types conditional on
`hasFPRegs()` rather than `hasVFP2Base()`. As a result a few
existing tests needed their llc command lines updating to use
`-mattr=-fpregs` as their method of turning off all hardware FP
support.
Reviewers: dmgreen, samparker, SjoerdMeijer
Subscribers: javed.absar, kristof.beyls, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60708
llvm-svn: 364329
2019-06-25 16:48:46 +00:00
|
|
|
Opc = Subtarget.hasNEON() ? ARM::VORRq : ARM::MVE_VORR;
|
2011-08-20 00:17:25 +00:00
|
|
|
|
|
|
|
if (Opc) {
|
|
|
|
MachineInstrBuilder MIB = BuildMI(MBB, I, DL, get(Opc), DestReg);
|
2011-07-15 18:46:47 +00:00
|
|
|
MIB.addReg(SrcReg, getKillRegState(KillSrc));
|
[ARM] Code-generation infrastructure for MVE.
This provides the low-level support to start using MVE vector types in
LLVM IR, loading and storing them, passing them to __asm__ statements
containing hand-written MVE vector instructions, and *if* you have the
hard-float ABI turned on, using them as function parameters.
(In the soft-float ABI, vector types are passed in integer registers,
and combining all those 32-bit integers into a q-reg requires support
for selection DAG nodes like insert_vector_elt and build_vector which
aren't implemented yet for MVE. In fact I've also had to add
`arm_aapcs_vfpcc` to a couple of existing tests to avoid that
problem.)
Specifically, this commit adds support for:
* spills, reloads and register moves for MVE vector registers
* ditto for the VPT predication mask that lives in VPR.P0
* make all the MVE vector types legal in ISel, and provide selection
DAG patterns for BITCAST, LOAD and STORE
* make loads and stores of scalar FP types conditional on
`hasFPRegs()` rather than `hasVFP2Base()`. As a result a few
existing tests needed their llc command lines updating to use
`-mattr=-fpregs` as their method of turning off all hardware FP
support.
Reviewers: dmgreen, samparker, SjoerdMeijer
Subscribers: javed.absar, kristof.beyls, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60708
llvm-svn: 364329
2019-06-25 16:48:46 +00:00
|
|
|
if (Opc == ARM::VORRq || Opc == ARM::MVE_VORR)
|
2011-08-20 00:17:25 +00:00
|
|
|
MIB.addReg(SrcReg, getKillRegState(KillSrc));
|
[ARM] Code-generation infrastructure for MVE.
This provides the low-level support to start using MVE vector types in
LLVM IR, loading and storing them, passing them to __asm__ statements
containing hand-written MVE vector instructions, and *if* you have the
hard-float ABI turned on, using them as function parameters.
(In the soft-float ABI, vector types are passed in integer registers,
and combining all those 32-bit integers into a q-reg requires support
for selection DAG nodes like insert_vector_elt and build_vector which
aren't implemented yet for MVE. In fact I've also had to add
`arm_aapcs_vfpcc` to a couple of existing tests to avoid that
problem.)
Specifically, this commit adds support for:
* spills, reloads and register moves for MVE vector registers
* ditto for the VPT predication mask that lives in VPR.P0
* make all the MVE vector types legal in ISel, and provide selection
DAG patterns for BITCAST, LOAD and STORE
* make loads and stores of scalar FP types conditional on
`hasFPRegs()` rather than `hasVFP2Base()`. As a result a few
existing tests needed their llc command lines updating to use
`-mattr=-fpregs` as their method of turning off all hardware FP
support.
Reviewers: dmgreen, samparker, SjoerdMeijer
Subscribers: javed.absar, kristof.beyls, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60708
llvm-svn: 364329
2019-06-25 16:48:46 +00:00
|
|
|
if (Opc == ARM::MVE_VORR)
|
|
|
|
addUnpredicatedMveVpredROp(MIB, DestReg);
|
|
|
|
else
|
|
|
|
MIB.add(predOps(ARMCC::AL));
|
2011-08-20 00:17:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-03-29 21:10:40 +00:00
|
|
|
// Handle register classes that require multiple instructions.
|
|
|
|
unsigned BeginIdx = 0;
|
|
|
|
unsigned SubRegs = 0;
|
2012-08-29 04:41:37 +00:00
|
|
|
int Spacing = 1;
|
2012-03-29 21:10:40 +00:00
|
|
|
|
|
|
|
// Use VORRq when possible.
|
2013-10-22 02:29:35 +00:00
|
|
|
if (ARM::QQPRRegClass.contains(DestReg, SrcReg)) {
|
[ARM] Code-generation infrastructure for MVE.
This provides the low-level support to start using MVE vector types in
LLVM IR, loading and storing them, passing them to __asm__ statements
containing hand-written MVE vector instructions, and *if* you have the
hard-float ABI turned on, using them as function parameters.
(In the soft-float ABI, vector types are passed in integer registers,
and combining all those 32-bit integers into a q-reg requires support
for selection DAG nodes like insert_vector_elt and build_vector which
aren't implemented yet for MVE. In fact I've also had to add
`arm_aapcs_vfpcc` to a couple of existing tests to avoid that
problem.)
Specifically, this commit adds support for:
* spills, reloads and register moves for MVE vector registers
* ditto for the VPT predication mask that lives in VPR.P0
* make all the MVE vector types legal in ISel, and provide selection
DAG patterns for BITCAST, LOAD and STORE
* make loads and stores of scalar FP types conditional on
`hasFPRegs()` rather than `hasVFP2Base()`. As a result a few
existing tests needed their llc command lines updating to use
`-mattr=-fpregs` as their method of turning off all hardware FP
support.
Reviewers: dmgreen, samparker, SjoerdMeijer
Subscribers: javed.absar, kristof.beyls, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60708
llvm-svn: 364329
2019-06-25 16:48:46 +00:00
|
|
|
Opc = Subtarget.hasNEON() ? ARM::VORRq : ARM::MVE_VORR;
|
2013-10-22 02:29:35 +00:00
|
|
|
BeginIdx = ARM::qsub_0;
|
|
|
|
SubRegs = 2;
|
|
|
|
} else if (ARM::QQQQPRRegClass.contains(DestReg, SrcReg)) {
|
[ARM] Code-generation infrastructure for MVE.
This provides the low-level support to start using MVE vector types in
LLVM IR, loading and storing them, passing them to __asm__ statements
containing hand-written MVE vector instructions, and *if* you have the
hard-float ABI turned on, using them as function parameters.
(In the soft-float ABI, vector types are passed in integer registers,
and combining all those 32-bit integers into a q-reg requires support
for selection DAG nodes like insert_vector_elt and build_vector which
aren't implemented yet for MVE. In fact I've also had to add
`arm_aapcs_vfpcc` to a couple of existing tests to avoid that
problem.)
Specifically, this commit adds support for:
* spills, reloads and register moves for MVE vector registers
* ditto for the VPT predication mask that lives in VPR.P0
* make all the MVE vector types legal in ISel, and provide selection
DAG patterns for BITCAST, LOAD and STORE
* make loads and stores of scalar FP types conditional on
`hasFPRegs()` rather than `hasVFP2Base()`. As a result a few
existing tests needed their llc command lines updating to use
`-mattr=-fpregs` as their method of turning off all hardware FP
support.
Reviewers: dmgreen, samparker, SjoerdMeijer
Subscribers: javed.absar, kristof.beyls, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60708
llvm-svn: 364329
2019-06-25 16:48:46 +00:00
|
|
|
Opc = Subtarget.hasNEON() ? ARM::VORRq : ARM::MVE_VORR;
|
2013-10-22 02:29:35 +00:00
|
|
|
BeginIdx = ARM::qsub_0;
|
|
|
|
SubRegs = 4;
|
2012-03-29 21:10:40 +00:00
|
|
|
// Fall back to VMOVD.
|
2013-10-22 02:29:35 +00:00
|
|
|
} else if (ARM::DPairRegClass.contains(DestReg, SrcReg)) {
|
|
|
|
Opc = ARM::VMOVD;
|
|
|
|
BeginIdx = ARM::dsub_0;
|
|
|
|
SubRegs = 2;
|
|
|
|
} else if (ARM::DTripleRegClass.contains(DestReg, SrcReg)) {
|
|
|
|
Opc = ARM::VMOVD;
|
|
|
|
BeginIdx = ARM::dsub_0;
|
|
|
|
SubRegs = 3;
|
|
|
|
} else if (ARM::DQuadRegClass.contains(DestReg, SrcReg)) {
|
|
|
|
Opc = ARM::VMOVD;
|
|
|
|
BeginIdx = ARM::dsub_0;
|
|
|
|
SubRegs = 4;
|
|
|
|
} else if (ARM::GPRPairRegClass.contains(DestReg, SrcReg)) {
|
2013-10-22 02:29:37 +00:00
|
|
|
Opc = Subtarget.isThumb2() ? ARM::tMOVr : ARM::MOVr;
|
2013-10-22 02:29:35 +00:00
|
|
|
BeginIdx = ARM::gsub_0;
|
|
|
|
SubRegs = 2;
|
|
|
|
} else if (ARM::DPairSpcRegClass.contains(DestReg, SrcReg)) {
|
|
|
|
Opc = ARM::VMOVD;
|
|
|
|
BeginIdx = ARM::dsub_0;
|
|
|
|
SubRegs = 2;
|
|
|
|
Spacing = 2;
|
|
|
|
} else if (ARM::DTripleSpcRegClass.contains(DestReg, SrcReg)) {
|
|
|
|
Opc = ARM::VMOVD;
|
|
|
|
BeginIdx = ARM::dsub_0;
|
|
|
|
SubRegs = 3;
|
|
|
|
Spacing = 2;
|
|
|
|
} else if (ARM::DQuadSpcRegClass.contains(DestReg, SrcReg)) {
|
|
|
|
Opc = ARM::VMOVD;
|
|
|
|
BeginIdx = ARM::dsub_0;
|
|
|
|
SubRegs = 4;
|
|
|
|
Spacing = 2;
|
[ARM] Replace fp-only-sp and d16 with fp64 and d32.
Those two subtarget features were awkward because their semantics are
reversed: each one indicates the _lack_ of support for something in
the architecture, rather than the presence. As a consequence, you
don't get the behavior you want if you combine two sets of feature
bits.
Each SubtargetFeature for an FP architecture version now comes in four
versions, one for each combination of those options. So you can still
say (for example) '+vfp2' in a feature string and it will mean what
it's always meant, but there's a new string '+vfp2d16sp' meaning the
version without those extra options.
A lot of this change is just mechanically replacing positive checks
for the old features with negative checks for the new ones. But one
more interesting change is that I've rearranged getFPUFeatures() so
that the main FPU feature is appended to the output list *before*
rather than after the features derived from the Restriction field, so
that -fp64 and -d32 can override defaults added by the main feature.
Reviewers: dmgreen, samparker, SjoerdMeijer
Subscribers: srhines, javed.absar, eraman, kristof.beyls, hiraditya, zzheng, Petar.Avramovic, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D60691
llvm-svn: 361845
2019-05-28 16:13:20 +00:00
|
|
|
} else if (ARM::DPRRegClass.contains(DestReg, SrcReg) &&
|
|
|
|
!Subtarget.hasFP64()) {
|
2014-08-21 12:50:31 +00:00
|
|
|
Opc = ARM::VMOVS;
|
|
|
|
BeginIdx = ARM::ssub_0;
|
|
|
|
SubRegs = 2;
|
2014-10-01 19:21:03 +00:00
|
|
|
} else if (SrcReg == ARM::CPSR) {
|
|
|
|
copyFromCPSR(MBB, I, DestReg, KillSrc, Subtarget);
|
|
|
|
return;
|
|
|
|
} else if (DestReg == ARM::CPSR) {
|
|
|
|
copyToCPSR(MBB, I, SrcReg, KillSrc, Subtarget);
|
|
|
|
return;
|
[ARM] Code-generation infrastructure for MVE.
This provides the low-level support to start using MVE vector types in
LLVM IR, loading and storing them, passing them to __asm__ statements
containing hand-written MVE vector instructions, and *if* you have the
hard-float ABI turned on, using them as function parameters.
(In the soft-float ABI, vector types are passed in integer registers,
and combining all those 32-bit integers into a q-reg requires support
for selection DAG nodes like insert_vector_elt and build_vector which
aren't implemented yet for MVE. In fact I've also had to add
`arm_aapcs_vfpcc` to a couple of existing tests to avoid that
problem.)
Specifically, this commit adds support for:
* spills, reloads and register moves for MVE vector registers
* ditto for the VPT predication mask that lives in VPR.P0
* make all the MVE vector types legal in ISel, and provide selection
DAG patterns for BITCAST, LOAD and STORE
* make loads and stores of scalar FP types conditional on
`hasFPRegs()` rather than `hasVFP2Base()`. As a result a few
existing tests needed their llc command lines updating to use
`-mattr=-fpregs` as their method of turning off all hardware FP
support.
Reviewers: dmgreen, samparker, SjoerdMeijer
Subscribers: javed.absar, kristof.beyls, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60708
llvm-svn: 364329
2019-06-25 16:48:46 +00:00
|
|
|
} else if (DestReg == ARM::VPR) {
|
2019-06-27 12:41:12 +00:00
|
|
|
assert(ARM::GPRRegClass.contains(SrcReg));
|
[ARM] Code-generation infrastructure for MVE.
This provides the low-level support to start using MVE vector types in
LLVM IR, loading and storing them, passing them to __asm__ statements
containing hand-written MVE vector instructions, and *if* you have the
hard-float ABI turned on, using them as function parameters.
(In the soft-float ABI, vector types are passed in integer registers,
and combining all those 32-bit integers into a q-reg requires support
for selection DAG nodes like insert_vector_elt and build_vector which
aren't implemented yet for MVE. In fact I've also had to add
`arm_aapcs_vfpcc` to a couple of existing tests to avoid that
problem.)
Specifically, this commit adds support for:
* spills, reloads and register moves for MVE vector registers
* ditto for the VPT predication mask that lives in VPR.P0
* make all the MVE vector types legal in ISel, and provide selection
DAG patterns for BITCAST, LOAD and STORE
* make loads and stores of scalar FP types conditional on
`hasFPRegs()` rather than `hasVFP2Base()`. As a result a few
existing tests needed their llc command lines updating to use
`-mattr=-fpregs` as their method of turning off all hardware FP
support.
Reviewers: dmgreen, samparker, SjoerdMeijer
Subscribers: javed.absar, kristof.beyls, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60708
llvm-svn: 364329
2019-06-25 16:48:46 +00:00
|
|
|
BuildMI(MBB, I, I->getDebugLoc(), get(ARM::VMSR_P0), DestReg)
|
|
|
|
.addReg(SrcReg, getKillRegState(KillSrc))
|
|
|
|
.add(predOps(ARMCC::AL));
|
|
|
|
return;
|
|
|
|
} else if (SrcReg == ARM::VPR) {
|
2019-06-27 12:41:12 +00:00
|
|
|
assert(ARM::GPRRegClass.contains(DestReg));
|
[ARM] Code-generation infrastructure for MVE.
This provides the low-level support to start using MVE vector types in
LLVM IR, loading and storing them, passing them to __asm__ statements
containing hand-written MVE vector instructions, and *if* you have the
hard-float ABI turned on, using them as function parameters.
(In the soft-float ABI, vector types are passed in integer registers,
and combining all those 32-bit integers into a q-reg requires support
for selection DAG nodes like insert_vector_elt and build_vector which
aren't implemented yet for MVE. In fact I've also had to add
`arm_aapcs_vfpcc` to a couple of existing tests to avoid that
problem.)
Specifically, this commit adds support for:
* spills, reloads and register moves for MVE vector registers
* ditto for the VPT predication mask that lives in VPR.P0
* make all the MVE vector types legal in ISel, and provide selection
DAG patterns for BITCAST, LOAD and STORE
* make loads and stores of scalar FP types conditional on
`hasFPRegs()` rather than `hasVFP2Base()`. As a result a few
existing tests needed their llc command lines updating to use
`-mattr=-fpregs` as their method of turning off all hardware FP
support.
Reviewers: dmgreen, samparker, SjoerdMeijer
Subscribers: javed.absar, kristof.beyls, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60708
llvm-svn: 364329
2019-06-25 16:48:46 +00:00
|
|
|
BuildMI(MBB, I, I->getDebugLoc(), get(ARM::VMRS_P0), DestReg)
|
|
|
|
.addReg(SrcReg, getKillRegState(KillSrc))
|
|
|
|
.add(predOps(ARMCC::AL));
|
|
|
|
return;
|
|
|
|
} else if (DestReg == ARM::FPSCR_NZCV) {
|
2019-06-27 12:41:12 +00:00
|
|
|
assert(ARM::GPRRegClass.contains(SrcReg));
|
[ARM] Code-generation infrastructure for MVE.
This provides the low-level support to start using MVE vector types in
LLVM IR, loading and storing them, passing them to __asm__ statements
containing hand-written MVE vector instructions, and *if* you have the
hard-float ABI turned on, using them as function parameters.
(In the soft-float ABI, vector types are passed in integer registers,
and combining all those 32-bit integers into a q-reg requires support
for selection DAG nodes like insert_vector_elt and build_vector which
aren't implemented yet for MVE. In fact I've also had to add
`arm_aapcs_vfpcc` to a couple of existing tests to avoid that
problem.)
Specifically, this commit adds support for:
* spills, reloads and register moves for MVE vector registers
* ditto for the VPT predication mask that lives in VPR.P0
* make all the MVE vector types legal in ISel, and provide selection
DAG patterns for BITCAST, LOAD and STORE
* make loads and stores of scalar FP types conditional on
`hasFPRegs()` rather than `hasVFP2Base()`. As a result a few
existing tests needed their llc command lines updating to use
`-mattr=-fpregs` as their method of turning off all hardware FP
support.
Reviewers: dmgreen, samparker, SjoerdMeijer
Subscribers: javed.absar, kristof.beyls, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60708
llvm-svn: 364329
2019-06-25 16:48:46 +00:00
|
|
|
BuildMI(MBB, I, I->getDebugLoc(), get(ARM::VMSR_FPSCR_NZCVQC), DestReg)
|
|
|
|
.addReg(SrcReg, getKillRegState(KillSrc))
|
|
|
|
.add(predOps(ARMCC::AL));
|
|
|
|
return;
|
|
|
|
} else if (SrcReg == ARM::FPSCR_NZCV) {
|
2019-06-27 12:41:12 +00:00
|
|
|
assert(ARM::GPRRegClass.contains(DestReg));
|
[ARM] Code-generation infrastructure for MVE.
This provides the low-level support to start using MVE vector types in
LLVM IR, loading and storing them, passing them to __asm__ statements
containing hand-written MVE vector instructions, and *if* you have the
hard-float ABI turned on, using them as function parameters.
(In the soft-float ABI, vector types are passed in integer registers,
and combining all those 32-bit integers into a q-reg requires support
for selection DAG nodes like insert_vector_elt and build_vector which
aren't implemented yet for MVE. In fact I've also had to add
`arm_aapcs_vfpcc` to a couple of existing tests to avoid that
problem.)
Specifically, this commit adds support for:
* spills, reloads and register moves for MVE vector registers
* ditto for the VPT predication mask that lives in VPR.P0
* make all the MVE vector types legal in ISel, and provide selection
DAG patterns for BITCAST, LOAD and STORE
* make loads and stores of scalar FP types conditional on
`hasFPRegs()` rather than `hasVFP2Base()`. As a result a few
existing tests needed their llc command lines updating to use
`-mattr=-fpregs` as their method of turning off all hardware FP
support.
Reviewers: dmgreen, samparker, SjoerdMeijer
Subscribers: javed.absar, kristof.beyls, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60708
llvm-svn: 364329
2019-06-25 16:48:46 +00:00
|
|
|
BuildMI(MBB, I, I->getDebugLoc(), get(ARM::VMRS_FPSCR_NZCVQC), DestReg)
|
|
|
|
.addReg(SrcReg, getKillRegState(KillSrc))
|
|
|
|
.add(predOps(ARMCC::AL));
|
|
|
|
return;
|
2013-10-22 02:29:35 +00:00
|
|
|
}
|
2012-03-29 21:10:40 +00:00
|
|
|
|
2012-08-29 04:41:37 +00:00
|
|
|
assert(Opc && "Impossible reg-to-reg copy");
|
2012-08-29 01:58:52 +00:00
|
|
|
|
|
|
|
const TargetRegisterInfo *TRI = &getRegisterInfo();
|
|
|
|
MachineInstrBuilder Mov;
|
2012-08-29 01:58:55 +00:00
|
|
|
|
|
|
|
// Copy register tuples backward when the first Dest reg overlaps with SrcReg.
|
|
|
|
if (TRI->regsOverlap(SrcReg, TRI->getSubReg(DestReg, BeginIdx))) {
|
2013-10-22 02:29:35 +00:00
|
|
|
BeginIdx = BeginIdx + ((SubRegs - 1) * Spacing);
|
2012-08-29 01:58:55 +00:00
|
|
|
Spacing = -Spacing;
|
|
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
|
|
SmallSet<unsigned, 4> DstRegs;
|
|
|
|
#endif
|
2012-08-29 01:58:52 +00:00
|
|
|
for (unsigned i = 0; i != SubRegs; ++i) {
|
Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Partial reverts in:
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
X86FixupLEAs.cpp - Some functions return unsigned and arguably should be MCRegister
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
HexagonBitSimplify.cpp - Function takes BitTracker::RegisterRef which appears to be unsigned&
MachineVerifier.cpp - Ambiguous operator==() given MCRegister and const Register
PPCFastISel.cpp - No Register::operator-=()
PeepholeOptimizer.cpp - TargetInstrInfo::optimizeLoadInstr() takes an unsigned&
MachineTraceMetrics.cpp - MachineTraceMetrics lacks a suitable constructor
Manual fixups in:
ARMFastISel.cpp - ARMEmitLoad() now takes a Register& instead of unsigned&
HexagonSplitDouble.cpp - Ternary operator was ambiguous between unsigned/Register
HexagonConstExtenders.cpp - Has a local class named Register, used llvm::Register instead of Register.
PPCFastISel.cpp - PPCEmitLoad() now takes a Register& instead of unsigned&
Depends on D65919
Reviewers: arsenm, bogner, craig.topper, RKSimon
Reviewed By: arsenm
Subscribers: RKSimon, craig.topper, lenary, aemerson, wuzish, jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65962
llvm-svn: 369041
2019-08-15 19:22:08 +00:00
|
|
|
Register Dst = TRI->getSubReg(DestReg, BeginIdx + i * Spacing);
|
|
|
|
Register Src = TRI->getSubReg(SrcReg, BeginIdx + i * Spacing);
|
2012-08-29 01:58:52 +00:00
|
|
|
assert(Dst && Src && "Bad sub-register");
|
2012-08-29 01:58:55 +00:00
|
|
|
#ifndef NDEBUG
|
|
|
|
assert(!DstRegs.count(Src) && "destructive vector copy");
|
2012-08-29 04:41:37 +00:00
|
|
|
DstRegs.insert(Dst);
|
2012-08-29 01:58:55 +00:00
|
|
|
#endif
|
2013-10-22 02:29:35 +00:00
|
|
|
Mov = BuildMI(MBB, I, I->getDebugLoc(), get(Opc), Dst).addReg(Src);
|
[ARM] Code-generation infrastructure for MVE.
This provides the low-level support to start using MVE vector types in
LLVM IR, loading and storing them, passing them to __asm__ statements
containing hand-written MVE vector instructions, and *if* you have the
hard-float ABI turned on, using them as function parameters.
(In the soft-float ABI, vector types are passed in integer registers,
and combining all those 32-bit integers into a q-reg requires support
for selection DAG nodes like insert_vector_elt and build_vector which
aren't implemented yet for MVE. In fact I've also had to add
`arm_aapcs_vfpcc` to a couple of existing tests to avoid that
problem.)
Specifically, this commit adds support for:
* spills, reloads and register moves for MVE vector registers
* ditto for the VPT predication mask that lives in VPR.P0
* make all the MVE vector types legal in ISel, and provide selection
DAG patterns for BITCAST, LOAD and STORE
* make loads and stores of scalar FP types conditional on
`hasFPRegs()` rather than `hasVFP2Base()`. As a result a few
existing tests needed their llc command lines updating to use
`-mattr=-fpregs` as their method of turning off all hardware FP
support.
Reviewers: dmgreen, samparker, SjoerdMeijer
Subscribers: javed.absar, kristof.beyls, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60708
llvm-svn: 364329
2019-06-25 16:48:46 +00:00
|
|
|
// VORR (NEON or MVE) takes two source operands.
|
|
|
|
if (Opc == ARM::VORRq || Opc == ARM::MVE_VORR) {
|
2012-08-29 01:58:52 +00:00
|
|
|
Mov.addReg(Src);
|
[ARM] Code-generation infrastructure for MVE.
This provides the low-level support to start using MVE vector types in
LLVM IR, loading and storing them, passing them to __asm__ statements
containing hand-written MVE vector instructions, and *if* you have the
hard-float ABI turned on, using them as function parameters.
(In the soft-float ABI, vector types are passed in integer registers,
and combining all those 32-bit integers into a q-reg requires support
for selection DAG nodes like insert_vector_elt and build_vector which
aren't implemented yet for MVE. In fact I've also had to add
`arm_aapcs_vfpcc` to a couple of existing tests to avoid that
problem.)
Specifically, this commit adds support for:
* spills, reloads and register moves for MVE vector registers
* ditto for the VPT predication mask that lives in VPR.P0
* make all the MVE vector types legal in ISel, and provide selection
DAG patterns for BITCAST, LOAD and STORE
* make loads and stores of scalar FP types conditional on
`hasFPRegs()` rather than `hasVFP2Base()`. As a result a few
existing tests needed their llc command lines updating to use
`-mattr=-fpregs` as their method of turning off all hardware FP
support.
Reviewers: dmgreen, samparker, SjoerdMeijer
Subscribers: javed.absar, kristof.beyls, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60708
llvm-svn: 364329
2019-06-25 16:48:46 +00:00
|
|
|
}
|
|
|
|
// MVE VORR takes predicate operands in place of an ordinary condition.
|
|
|
|
if (Opc == ARM::MVE_VORR)
|
|
|
|
addUnpredicatedMveVpredROp(Mov, Dst);
|
|
|
|
else
|
|
|
|
Mov = Mov.add(predOps(ARMCC::AL));
|
2013-07-12 23:33:03 +00:00
|
|
|
// MOVr can set CC.
|
|
|
|
if (Opc == ARM::MOVr)
|
2017-01-13 10:18:01 +00:00
|
|
|
Mov = Mov.add(condCodeOp());
|
2011-08-20 00:17:25 +00:00
|
|
|
}
|
2012-08-29 01:58:52 +00:00
|
|
|
// Add implicit super-register defs and kills to the last instruction.
|
|
|
|
Mov->addRegisterDefined(DestReg, TRI);
|
|
|
|
if (KillSrc)
|
|
|
|
Mov->addRegisterKilled(SrcReg, TRI);
|
2009-07-08 16:09:28 +00:00
|
|
|
}
|
|
|
|
|
2019-11-08 11:19:58 +01:00
|
|
|
Optional<DestSourcePair>
|
|
|
|
ARMBaseInstrInfo::isCopyInstrImpl(const MachineInstr &MI) const {
|
2018-05-23 15:28:28 +00:00
|
|
|
// VMOVRRD is also a copy instruction but it requires
|
|
|
|
// special way of handling. It is more complex copy version
|
|
|
|
// and since that we are not considering it. For recognition
|
|
|
|
// of such instruction isExtractSubregLike MI interface fuction
|
|
|
|
// could be used.
|
|
|
|
// VORRq is considered as a move only if two inputs are
|
|
|
|
// the same register.
|
|
|
|
if (!MI.isMoveReg() ||
|
|
|
|
(MI.getOpcode() == ARM::VORRq &&
|
|
|
|
MI.getOperand(1).getReg() != MI.getOperand(2).getReg()))
|
2019-11-08 11:19:58 +01:00
|
|
|
return None;
|
|
|
|
return DestSourcePair{MI.getOperand(0), MI.getOperand(1)};
|
2018-05-23 15:28:28 +00:00
|
|
|
}
|
|
|
|
|
2020-02-27 09:58:24 -08:00
|
|
|
Optional<ParamLoadedValue>
|
|
|
|
ARMBaseInstrInfo::describeLoadedValue(const MachineInstr &MI,
|
|
|
|
Register Reg) const {
|
|
|
|
if (auto DstSrcPair = isCopyInstrImpl(MI)) {
|
|
|
|
Register DstReg = DstSrcPair->Destination->getReg();
|
|
|
|
|
|
|
|
// TODO: We don't handle cases where the forwarding reg is narrower/wider
|
|
|
|
// than the copy registers. Consider for example:
|
|
|
|
//
|
|
|
|
// s16 = VMOVS s0
|
|
|
|
// s17 = VMOVS s1
|
|
|
|
// call @callee(d0)
|
|
|
|
//
|
|
|
|
// We'd like to describe the call site value of d0 as d8, but this requires
|
|
|
|
// gathering and merging the descriptions for the two VMOVS instructions.
|
|
|
|
//
|
|
|
|
// We also don't handle the reverse situation, where the forwarding reg is
|
|
|
|
// narrower than the copy destination:
|
|
|
|
//
|
|
|
|
// d8 = VMOVD d0
|
|
|
|
// call @callee(s1)
|
|
|
|
//
|
|
|
|
// We need to produce a fragment description (the call site value of s1 is
|
|
|
|
// /not/ just d8).
|
|
|
|
if (DstReg != Reg)
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
return TargetInstrInfo::describeLoadedValue(MI, Reg);
|
|
|
|
}
|
|
|
|
|
2013-04-21 11:57:07 +00:00
|
|
|
const MachineInstrBuilder &
|
|
|
|
ARMBaseInstrInfo::AddDReg(MachineInstrBuilder &MIB, unsigned Reg,
|
|
|
|
unsigned SubIdx, unsigned State,
|
|
|
|
const TargetRegisterInfo *TRI) const {
|
2010-05-07 00:24:52 +00:00
|
|
|
if (!SubIdx)
|
|
|
|
return MIB.addReg(Reg, State);
|
|
|
|
|
2019-08-01 23:27:28 +00:00
|
|
|
if (Register::isPhysicalRegister(Reg))
|
2010-05-07 00:24:52 +00:00
|
|
|
return MIB.addReg(TRI->getSubReg(Reg, SubIdx), State);
|
|
|
|
return MIB.addReg(Reg, State, SubIdx);
|
|
|
|
}
|
|
|
|
|
2009-07-08 16:09:28 +00:00
|
|
|
void ARMBaseInstrInfo::
|
|
|
|
storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
|
[NFC] unsigned->Register in storeRegTo/loadRegFromStack
Summary:
This patch makes progress on the 'unsigned -> Register' rewrite for
`TargetInstrInfo::loadRegFromStack` and `TII::storeRegToStack`.
Reviewers: arsenm, craig.topper, uweigand, jpienaar, atanasyan, venkatra, robertlytton, dylanmckay, t.p.northover, kparzysz, tstellar, k-ishizaka
Reviewed By: arsenm
Subscribers: wuzish, merge_guards_bot, jyknight, sdardis, nemanjai, jvesely, wdng, nhaehnle, hiraditya, kbarton, fedor.sergeev, asb, rbar, johnrusso, simoncook, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, rogfer01, MartinMosbeck, brucehoult, the_o, PkmX, jocewei, jsji, Jim, lenary, s.egerton, pzheng, sameer.abuasal, apazos, luismarques, kerbowa, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D73870
2020-02-03 14:22:06 +01:00
|
|
|
Register SrcReg, bool isKill, int FI,
|
2010-05-06 19:06:44 +00:00
|
|
|
const TargetRegisterClass *RC,
|
|
|
|
const TargetRegisterInfo *TRI) const {
|
2009-10-07 00:06:35 +00:00
|
|
|
MachineFunction &MF = *MBB.getParent();
|
2016-07-28 18:40:00 +00:00
|
|
|
MachineFrameInfo &MFI = MF.getFrameInfo();
|
[Alignment][NFC] Transitionning more getMachineMemOperand call sites
Summary:
This is patch is part of a series to introduce an Alignment type.
See this thread for context: http://lists.llvm.org/pipermail/llvm-dev/2019-July/133851.html
See this patch for the introduction of the type: https://reviews.llvm.org/D64790
Reviewers: courbet
Subscribers: arsenm, dylanmckay, sdardis, nemanjai, jvesely, nhaehnle, hiraditya, kbarton, jrtc27, atanasyan, Jim, kerbowa, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D77121
2020-03-31 08:05:00 +00:00
|
|
|
Align Alignment = MFI.getObjectAlign(FI);
|
2009-10-07 00:06:35 +00:00
|
|
|
|
2015-08-11 23:09:45 +00:00
|
|
|
MachineMemOperand *MMO = MF.getMachineMemOperand(
|
|
|
|
MachinePointerInfo::getFixedStack(MF, FI), MachineMemOperand::MOStore,
|
[Alignment][NFC] Transitionning more getMachineMemOperand call sites
Summary:
This is patch is part of a series to introduce an Alignment type.
See this thread for context: http://lists.llvm.org/pipermail/llvm-dev/2019-July/133851.html
See this patch for the introduction of the type: https://reviews.llvm.org/D64790
Reviewers: courbet
Subscribers: arsenm, dylanmckay, sdardis, nemanjai, jvesely, nhaehnle, hiraditya, kbarton, jrtc27, atanasyan, Jim, kerbowa, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D77121
2020-03-31 08:05:00 +00:00
|
|
|
MFI.getObjectSize(FI), Alignment);
|
2009-07-08 16:09:28 +00:00
|
|
|
|
2017-04-24 18:55:33 +00:00
|
|
|
switch (TRI->getSpillSize(*RC)) {
|
2018-02-14 15:09:09 +00:00
|
|
|
case 2:
|
|
|
|
if (ARM::HPRRegClass.hasSubClassEq(RC)) {
|
2018-10-05 22:00:13 +00:00
|
|
|
BuildMI(MBB, I, DebugLoc(), get(ARM::VSTRH))
|
2018-02-14 15:09:09 +00:00
|
|
|
.addReg(SrcReg, getKillRegState(isKill))
|
|
|
|
.addFrameIndex(FI)
|
|
|
|
.addImm(0)
|
|
|
|
.addMemOperand(MMO)
|
|
|
|
.add(predOps(ARMCC::AL));
|
|
|
|
} else
|
|
|
|
llvm_unreachable("Unknown reg class!");
|
|
|
|
break;
|
2011-08-10 17:21:20 +00:00
|
|
|
case 4:
|
|
|
|
if (ARM::GPRRegClass.hasSubClassEq(RC)) {
|
2018-10-05 22:00:13 +00:00
|
|
|
BuildMI(MBB, I, DebugLoc(), get(ARM::STRi12))
|
2017-01-13 09:37:56 +00:00
|
|
|
.addReg(SrcReg, getKillRegState(isKill))
|
|
|
|
.addFrameIndex(FI)
|
|
|
|
.addImm(0)
|
|
|
|
.addMemOperand(MMO)
|
|
|
|
.add(predOps(ARMCC::AL));
|
2011-08-10 17:21:20 +00:00
|
|
|
} else if (ARM::SPRRegClass.hasSubClassEq(RC)) {
|
2018-10-05 22:00:13 +00:00
|
|
|
BuildMI(MBB, I, DebugLoc(), get(ARM::VSTRS))
|
2017-01-13 09:37:56 +00:00
|
|
|
.addReg(SrcReg, getKillRegState(isKill))
|
|
|
|
.addFrameIndex(FI)
|
|
|
|
.addImm(0)
|
|
|
|
.addMemOperand(MMO)
|
|
|
|
.add(predOps(ARMCC::AL));
|
[ARM] Code-generation infrastructure for MVE.
This provides the low-level support to start using MVE vector types in
LLVM IR, loading and storing them, passing them to __asm__ statements
containing hand-written MVE vector instructions, and *if* you have the
hard-float ABI turned on, using them as function parameters.
(In the soft-float ABI, vector types are passed in integer registers,
and combining all those 32-bit integers into a q-reg requires support
for selection DAG nodes like insert_vector_elt and build_vector which
aren't implemented yet for MVE. In fact I've also had to add
`arm_aapcs_vfpcc` to a couple of existing tests to avoid that
problem.)
Specifically, this commit adds support for:
* spills, reloads and register moves for MVE vector registers
* ditto for the VPT predication mask that lives in VPR.P0
* make all the MVE vector types legal in ISel, and provide selection
DAG patterns for BITCAST, LOAD and STORE
* make loads and stores of scalar FP types conditional on
`hasFPRegs()` rather than `hasVFP2Base()`. As a result a few
existing tests needed their llc command lines updating to use
`-mattr=-fpregs` as their method of turning off all hardware FP
support.
Reviewers: dmgreen, samparker, SjoerdMeijer
Subscribers: javed.absar, kristof.beyls, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60708
llvm-svn: 364329
2019-06-25 16:48:46 +00:00
|
|
|
} else if (ARM::VCCRRegClass.hasSubClassEq(RC)) {
|
|
|
|
BuildMI(MBB, I, DebugLoc(), get(ARM::VSTR_P0_off))
|
|
|
|
.addReg(SrcReg, getKillRegState(isKill))
|
|
|
|
.addFrameIndex(FI)
|
|
|
|
.addImm(0)
|
|
|
|
.addMemOperand(MMO)
|
|
|
|
.add(predOps(ARMCC::AL));
|
2011-08-10 17:21:20 +00:00
|
|
|
} else
|
|
|
|
llvm_unreachable("Unknown reg class!");
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
if (ARM::DPRRegClass.hasSubClassEq(RC)) {
|
2018-10-05 22:00:13 +00:00
|
|
|
BuildMI(MBB, I, DebugLoc(), get(ARM::VSTRD))
|
2017-01-13 09:37:56 +00:00
|
|
|
.addReg(SrcReg, getKillRegState(isKill))
|
|
|
|
.addFrameIndex(FI)
|
|
|
|
.addImm(0)
|
|
|
|
.addMemOperand(MMO)
|
|
|
|
.add(predOps(ARMCC::AL));
|
2012-10-26 21:29:15 +00:00
|
|
|
} else if (ARM::GPRPairRegClass.hasSubClassEq(RC)) {
|
2013-04-21 11:57:07 +00:00
|
|
|
if (Subtarget.hasV5TEOps()) {
|
2018-10-05 22:00:13 +00:00
|
|
|
MachineInstrBuilder MIB = BuildMI(MBB, I, DebugLoc(), get(ARM::STRD));
|
2013-04-21 11:57:07 +00:00
|
|
|
AddDReg(MIB, SrcReg, ARM::gsub_0, getKillRegState(isKill), TRI);
|
|
|
|
AddDReg(MIB, SrcReg, ARM::gsub_1, 0, TRI);
|
2017-01-13 09:37:56 +00:00
|
|
|
MIB.addFrameIndex(FI).addReg(0).addImm(0).addMemOperand(MMO)
|
|
|
|
.add(predOps(ARMCC::AL));
|
2013-04-21 11:57:07 +00:00
|
|
|
} else {
|
|
|
|
// Fallback to STM instruction, which has existed since the dawn of
|
|
|
|
// time.
|
2018-10-05 22:00:13 +00:00
|
|
|
MachineInstrBuilder MIB = BuildMI(MBB, I, DebugLoc(), get(ARM::STMIA))
|
2017-01-13 09:37:56 +00:00
|
|
|
.addFrameIndex(FI)
|
|
|
|
.addMemOperand(MMO)
|
|
|
|
.add(predOps(ARMCC::AL));
|
2013-04-21 11:57:07 +00:00
|
|
|
AddDReg(MIB, SrcReg, ARM::gsub_0, getKillRegState(isKill), TRI);
|
|
|
|
AddDReg(MIB, SrcReg, ARM::gsub_1, 0, TRI);
|
|
|
|
}
|
2011-08-10 17:21:20 +00:00
|
|
|
} else
|
|
|
|
llvm_unreachable("Unknown reg class!");
|
|
|
|
break;
|
|
|
|
case 16:
|
[ARM] Code-generation infrastructure for MVE.
This provides the low-level support to start using MVE vector types in
LLVM IR, loading and storing them, passing them to __asm__ statements
containing hand-written MVE vector instructions, and *if* you have the
hard-float ABI turned on, using them as function parameters.
(In the soft-float ABI, vector types are passed in integer registers,
and combining all those 32-bit integers into a q-reg requires support
for selection DAG nodes like insert_vector_elt and build_vector which
aren't implemented yet for MVE. In fact I've also had to add
`arm_aapcs_vfpcc` to a couple of existing tests to avoid that
problem.)
Specifically, this commit adds support for:
* spills, reloads and register moves for MVE vector registers
* ditto for the VPT predication mask that lives in VPR.P0
* make all the MVE vector types legal in ISel, and provide selection
DAG patterns for BITCAST, LOAD and STORE
* make loads and stores of scalar FP types conditional on
`hasFPRegs()` rather than `hasVFP2Base()`. As a result a few
existing tests needed their llc command lines updating to use
`-mattr=-fpregs` as their method of turning off all hardware FP
support.
Reviewers: dmgreen, samparker, SjoerdMeijer
Subscribers: javed.absar, kristof.beyls, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60708
llvm-svn: 364329
2019-06-25 16:48:46 +00:00
|
|
|
if (ARM::DPairRegClass.hasSubClassEq(RC) && Subtarget.hasNEON()) {
|
2012-01-05 00:26:57 +00:00
|
|
|
// Use aligned spills if the stack can be realigned.
|
[Alignment][NFC] Transitionning more getMachineMemOperand call sites
Summary:
This is patch is part of a series to introduce an Alignment type.
See this thread for context: http://lists.llvm.org/pipermail/llvm-dev/2019-July/133851.html
See this patch for the introduction of the type: https://reviews.llvm.org/D64790
Reviewers: courbet
Subscribers: arsenm, dylanmckay, sdardis, nemanjai, jvesely, nhaehnle, hiraditya, kbarton, jrtc27, atanasyan, Jim, kerbowa, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D77121
2020-03-31 08:05:00 +00:00
|
|
|
if (Alignment >= 16 && getRegisterInfo().canRealignStack(MF)) {
|
2018-10-05 22:00:13 +00:00
|
|
|
BuildMI(MBB, I, DebugLoc(), get(ARM::VST1q64))
|
2017-01-13 09:37:56 +00:00
|
|
|
.addFrameIndex(FI)
|
|
|
|
.addImm(16)
|
|
|
|
.addReg(SrcReg, getKillRegState(isKill))
|
|
|
|
.addMemOperand(MMO)
|
|
|
|
.add(predOps(ARMCC::AL));
|
2011-08-10 17:21:20 +00:00
|
|
|
} else {
|
2018-10-05 22:00:13 +00:00
|
|
|
BuildMI(MBB, I, DebugLoc(), get(ARM::VSTMQIA))
|
2017-01-13 09:37:56 +00:00
|
|
|
.addReg(SrcReg, getKillRegState(isKill))
|
|
|
|
.addFrameIndex(FI)
|
|
|
|
.addMemOperand(MMO)
|
|
|
|
.add(predOps(ARMCC::AL));
|
2011-08-10 17:21:20 +00:00
|
|
|
}
|
[ARM] Code-generation infrastructure for MVE.
This provides the low-level support to start using MVE vector types in
LLVM IR, loading and storing them, passing them to __asm__ statements
containing hand-written MVE vector instructions, and *if* you have the
hard-float ABI turned on, using them as function parameters.
(In the soft-float ABI, vector types are passed in integer registers,
and combining all those 32-bit integers into a q-reg requires support
for selection DAG nodes like insert_vector_elt and build_vector which
aren't implemented yet for MVE. In fact I've also had to add
`arm_aapcs_vfpcc` to a couple of existing tests to avoid that
problem.)
Specifically, this commit adds support for:
* spills, reloads and register moves for MVE vector registers
* ditto for the VPT predication mask that lives in VPR.P0
* make all the MVE vector types legal in ISel, and provide selection
DAG patterns for BITCAST, LOAD and STORE
* make loads and stores of scalar FP types conditional on
`hasFPRegs()` rather than `hasVFP2Base()`. As a result a few
existing tests needed their llc command lines updating to use
`-mattr=-fpregs` as their method of turning off all hardware FP
support.
Reviewers: dmgreen, samparker, SjoerdMeijer
Subscribers: javed.absar, kristof.beyls, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60708
llvm-svn: 364329
2019-06-25 16:48:46 +00:00
|
|
|
} else if (ARM::QPRRegClass.hasSubClassEq(RC) &&
|
|
|
|
Subtarget.hasMVEIntegerOps()) {
|
|
|
|
auto MIB = BuildMI(MBB, I, DebugLoc(), get(ARM::MVE_VSTRWU32));
|
|
|
|
MIB.addReg(SrcReg, getKillRegState(isKill))
|
|
|
|
.addFrameIndex(FI)
|
|
|
|
.addImm(0)
|
|
|
|
.addMemOperand(MMO);
|
|
|
|
addUnpredicatedMveVpredNOp(MIB);
|
2011-08-10 17:21:20 +00:00
|
|
|
} else
|
|
|
|
llvm_unreachable("Unknown reg class!");
|
|
|
|
break;
|
2012-08-04 13:16:12 +00:00
|
|
|
case 24:
|
|
|
|
if (ARM::DTripleRegClass.hasSubClassEq(RC)) {
|
|
|
|
// Use aligned spills if the stack can be realigned.
|
[Alignment][NFC] Transitionning more getMachineMemOperand call sites
Summary:
This is patch is part of a series to introduce an Alignment type.
See this thread for context: http://lists.llvm.org/pipermail/llvm-dev/2019-July/133851.html
See this patch for the introduction of the type: https://reviews.llvm.org/D64790
Reviewers: courbet
Subscribers: arsenm, dylanmckay, sdardis, nemanjai, jvesely, nhaehnle, hiraditya, kbarton, jrtc27, atanasyan, Jim, kerbowa, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D77121
2020-03-31 08:05:00 +00:00
|
|
|
if (Alignment >= 16 && getRegisterInfo().canRealignStack(MF) &&
|
2019-09-09 10:46:25 +00:00
|
|
|
Subtarget.hasNEON()) {
|
2018-10-05 22:00:13 +00:00
|
|
|
BuildMI(MBB, I, DebugLoc(), get(ARM::VST1d64TPseudo))
|
2017-01-13 09:37:56 +00:00
|
|
|
.addFrameIndex(FI)
|
|
|
|
.addImm(16)
|
|
|
|
.addReg(SrcReg, getKillRegState(isKill))
|
|
|
|
.addMemOperand(MMO)
|
|
|
|
.add(predOps(ARMCC::AL));
|
2012-08-04 13:16:12 +00:00
|
|
|
} else {
|
2018-10-05 22:00:13 +00:00
|
|
|
MachineInstrBuilder MIB = BuildMI(MBB, I, DebugLoc(),
|
|
|
|
get(ARM::VSTMDIA))
|
2017-01-13 09:37:56 +00:00
|
|
|
.addFrameIndex(FI)
|
|
|
|
.add(predOps(ARMCC::AL))
|
|
|
|
.addMemOperand(MMO);
|
2012-08-04 13:16:12 +00:00
|
|
|
MIB = AddDReg(MIB, SrcReg, ARM::dsub_0, getKillRegState(isKill), TRI);
|
|
|
|
MIB = AddDReg(MIB, SrcReg, ARM::dsub_1, 0, TRI);
|
|
|
|
AddDReg(MIB, SrcReg, ARM::dsub_2, 0, TRI);
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
llvm_unreachable("Unknown reg class!");
|
|
|
|
break;
|
2011-08-10 17:21:20 +00:00
|
|
|
case 32:
|
2012-08-04 13:16:12 +00:00
|
|
|
if (ARM::QQPRRegClass.hasSubClassEq(RC) || ARM::DQuadRegClass.hasSubClassEq(RC)) {
|
[Alignment][NFC] Transitionning more getMachineMemOperand call sites
Summary:
This is patch is part of a series to introduce an Alignment type.
See this thread for context: http://lists.llvm.org/pipermail/llvm-dev/2019-July/133851.html
See this patch for the introduction of the type: https://reviews.llvm.org/D64790
Reviewers: courbet
Subscribers: arsenm, dylanmckay, sdardis, nemanjai, jvesely, nhaehnle, hiraditya, kbarton, jrtc27, atanasyan, Jim, kerbowa, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D77121
2020-03-31 08:05:00 +00:00
|
|
|
if (Alignment >= 16 && getRegisterInfo().canRealignStack(MF) &&
|
2019-09-09 10:46:25 +00:00
|
|
|
Subtarget.hasNEON()) {
|
2011-08-10 17:21:20 +00:00
|
|
|
// FIXME: It's possible to only store part of the QQ register if the
|
|
|
|
// spilled def has a sub-register index.
|
2018-10-05 22:00:13 +00:00
|
|
|
BuildMI(MBB, I, DebugLoc(), get(ARM::VST1d64QPseudo))
|
2017-01-13 09:37:56 +00:00
|
|
|
.addFrameIndex(FI)
|
|
|
|
.addImm(16)
|
|
|
|
.addReg(SrcReg, getKillRegState(isKill))
|
|
|
|
.addMemOperand(MMO)
|
|
|
|
.add(predOps(ARMCC::AL));
|
2011-08-10 17:21:20 +00:00
|
|
|
} else {
|
2018-10-05 22:00:13 +00:00
|
|
|
MachineInstrBuilder MIB = BuildMI(MBB, I, DebugLoc(),
|
|
|
|
get(ARM::VSTMDIA))
|
2017-01-13 09:37:56 +00:00
|
|
|
.addFrameIndex(FI)
|
|
|
|
.add(predOps(ARMCC::AL))
|
|
|
|
.addMemOperand(MMO);
|
2011-08-10 17:21:20 +00:00
|
|
|
MIB = AddDReg(MIB, SrcReg, ARM::dsub_0, getKillRegState(isKill), TRI);
|
|
|
|
MIB = AddDReg(MIB, SrcReg, ARM::dsub_1, 0, TRI);
|
|
|
|
MIB = AddDReg(MIB, SrcReg, ARM::dsub_2, 0, TRI);
|
|
|
|
AddDReg(MIB, SrcReg, ARM::dsub_3, 0, TRI);
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
llvm_unreachable("Unknown reg class!");
|
|
|
|
break;
|
|
|
|
case 64:
|
|
|
|
if (ARM::QQQQPRRegClass.hasSubClassEq(RC)) {
|
2018-10-05 22:00:13 +00:00
|
|
|
MachineInstrBuilder MIB = BuildMI(MBB, I, DebugLoc(), get(ARM::VSTMDIA))
|
2017-01-13 09:37:56 +00:00
|
|
|
.addFrameIndex(FI)
|
|
|
|
.add(predOps(ARMCC::AL))
|
|
|
|
.addMemOperand(MMO);
|
2011-08-10 17:21:20 +00:00
|
|
|
MIB = AddDReg(MIB, SrcReg, ARM::dsub_0, getKillRegState(isKill), TRI);
|
|
|
|
MIB = AddDReg(MIB, SrcReg, ARM::dsub_1, 0, TRI);
|
|
|
|
MIB = AddDReg(MIB, SrcReg, ARM::dsub_2, 0, TRI);
|
|
|
|
MIB = AddDReg(MIB, SrcReg, ARM::dsub_3, 0, TRI);
|
|
|
|
MIB = AddDReg(MIB, SrcReg, ARM::dsub_4, 0, TRI);
|
|
|
|
MIB = AddDReg(MIB, SrcReg, ARM::dsub_5, 0, TRI);
|
|
|
|
MIB = AddDReg(MIB, SrcReg, ARM::dsub_6, 0, TRI);
|
|
|
|
AddDReg(MIB, SrcReg, ARM::dsub_7, 0, TRI);
|
|
|
|
} else
|
|
|
|
llvm_unreachable("Unknown reg class!");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
llvm_unreachable("Unknown reg class!");
|
2009-07-08 16:09:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
unsigned ARMBaseInstrInfo::isStoreToStackSlot(const MachineInstr &MI,
|
|
|
|
int &FrameIndex) const {
|
|
|
|
switch (MI.getOpcode()) {
|
2010-09-15 16:36:26 +00:00
|
|
|
default: break;
|
2010-10-27 23:12:14 +00:00
|
|
|
case ARM::STRrs:
|
2010-09-15 16:36:26 +00:00
|
|
|
case ARM::t2STRs: // FIXME: don't use t2STRs to access frame.
|
2016-06-30 00:01:54 +00:00
|
|
|
if (MI.getOperand(1).isFI() && MI.getOperand(2).isReg() &&
|
|
|
|
MI.getOperand(3).isImm() && MI.getOperand(2).getReg() == 0 &&
|
|
|
|
MI.getOperand(3).getImm() == 0) {
|
|
|
|
FrameIndex = MI.getOperand(1).getIndex();
|
|
|
|
return MI.getOperand(0).getReg();
|
2010-09-15 16:36:26 +00:00
|
|
|
}
|
|
|
|
break;
|
2010-10-27 23:12:14 +00:00
|
|
|
case ARM::STRi12:
|
2010-09-15 16:36:26 +00:00
|
|
|
case ARM::t2STRi12:
|
2011-06-29 20:26:39 +00:00
|
|
|
case ARM::tSTRspi:
|
2010-09-15 16:36:26 +00:00
|
|
|
case ARM::VSTRD:
|
|
|
|
case ARM::VSTRS:
|
2016-06-30 00:01:54 +00:00
|
|
|
if (MI.getOperand(1).isFI() && MI.getOperand(2).isImm() &&
|
|
|
|
MI.getOperand(2).getImm() == 0) {
|
|
|
|
FrameIndex = MI.getOperand(1).getIndex();
|
|
|
|
return MI.getOperand(0).getReg();
|
2010-09-15 16:36:26 +00:00
|
|
|
}
|
|
|
|
break;
|
[ARM] Code-generation infrastructure for MVE.
This provides the low-level support to start using MVE vector types in
LLVM IR, loading and storing them, passing them to __asm__ statements
containing hand-written MVE vector instructions, and *if* you have the
hard-float ABI turned on, using them as function parameters.
(In the soft-float ABI, vector types are passed in integer registers,
and combining all those 32-bit integers into a q-reg requires support
for selection DAG nodes like insert_vector_elt and build_vector which
aren't implemented yet for MVE. In fact I've also had to add
`arm_aapcs_vfpcc` to a couple of existing tests to avoid that
problem.)
Specifically, this commit adds support for:
* spills, reloads and register moves for MVE vector registers
* ditto for the VPT predication mask that lives in VPR.P0
* make all the MVE vector types legal in ISel, and provide selection
DAG patterns for BITCAST, LOAD and STORE
* make loads and stores of scalar FP types conditional on
`hasFPRegs()` rather than `hasVFP2Base()`. As a result a few
existing tests needed their llc command lines updating to use
`-mattr=-fpregs` as their method of turning off all hardware FP
support.
Reviewers: dmgreen, samparker, SjoerdMeijer
Subscribers: javed.absar, kristof.beyls, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60708
llvm-svn: 364329
2019-06-25 16:48:46 +00:00
|
|
|
case ARM::VSTR_P0_off:
|
|
|
|
if (MI.getOperand(0).isFI() && MI.getOperand(1).isImm() &&
|
|
|
|
MI.getOperand(1).getImm() == 0) {
|
|
|
|
FrameIndex = MI.getOperand(0).getIndex();
|
|
|
|
return ARM::P0;
|
|
|
|
}
|
|
|
|
break;
|
2012-03-05 19:33:30 +00:00
|
|
|
case ARM::VST1q64:
|
2012-08-04 13:22:14 +00:00
|
|
|
case ARM::VST1d64TPseudo:
|
|
|
|
case ARM::VST1d64QPseudo:
|
2016-06-30 00:01:54 +00:00
|
|
|
if (MI.getOperand(0).isFI() && MI.getOperand(2).getSubReg() == 0) {
|
|
|
|
FrameIndex = MI.getOperand(0).getIndex();
|
|
|
|
return MI.getOperand(2).getReg();
|
2010-09-15 17:27:09 +00:00
|
|
|
}
|
2010-09-15 21:40:09 +00:00
|
|
|
break;
|
2010-11-16 01:16:36 +00:00
|
|
|
case ARM::VSTMQIA:
|
2016-06-30 00:01:54 +00:00
|
|
|
if (MI.getOperand(1).isFI() && MI.getOperand(0).getSubReg() == 0) {
|
|
|
|
FrameIndex = MI.getOperand(1).getIndex();
|
|
|
|
return MI.getOperand(0).getReg();
|
2010-09-15 17:27:09 +00:00
|
|
|
}
|
|
|
|
break;
|
2010-09-15 16:36:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
unsigned ARMBaseInstrInfo::isStoreToStackSlotPostFE(const MachineInstr &MI,
|
2011-08-08 21:45:32 +00:00
|
|
|
int &FrameIndex) const {
|
2018-09-05 08:59:50 +00:00
|
|
|
SmallVector<const MachineMemOperand *, 1> Accesses;
|
2019-03-25 22:42:30 +00:00
|
|
|
if (MI.mayStore() && hasStoreToStackSlot(MI, Accesses) &&
|
|
|
|
Accesses.size() == 1) {
|
2018-09-05 08:59:50 +00:00
|
|
|
FrameIndex =
|
|
|
|
cast<FixedStackPseudoSourceValue>(Accesses.front()->getPseudoValue())
|
|
|
|
->getFrameIndex();
|
2018-09-03 09:15:58 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2011-08-08 21:45:32 +00:00
|
|
|
}
|
|
|
|
|
2009-07-08 16:09:28 +00:00
|
|
|
void ARMBaseInstrInfo::
|
|
|
|
loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
|
[NFC] unsigned->Register in storeRegTo/loadRegFromStack
Summary:
This patch makes progress on the 'unsigned -> Register' rewrite for
`TargetInstrInfo::loadRegFromStack` and `TII::storeRegToStack`.
Reviewers: arsenm, craig.topper, uweigand, jpienaar, atanasyan, venkatra, robertlytton, dylanmckay, t.p.northover, kparzysz, tstellar, k-ishizaka
Reviewed By: arsenm
Subscribers: wuzish, merge_guards_bot, jyknight, sdardis, nemanjai, jvesely, wdng, nhaehnle, hiraditya, kbarton, fedor.sergeev, asb, rbar, johnrusso, simoncook, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, rogfer01, MartinMosbeck, brucehoult, the_o, PkmX, jocewei, jsji, Jim, lenary, s.egerton, pzheng, sameer.abuasal, apazos, luismarques, kerbowa, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D73870
2020-02-03 14:22:06 +01:00
|
|
|
Register DestReg, int FI,
|
2010-05-06 19:06:44 +00:00
|
|
|
const TargetRegisterClass *RC,
|
|
|
|
const TargetRegisterInfo *TRI) const {
|
2010-04-02 20:16:16 +00:00
|
|
|
DebugLoc DL;
|
2009-07-08 16:09:28 +00:00
|
|
|
if (I != MBB.end()) DL = I->getDebugLoc();
|
2009-10-07 00:06:35 +00:00
|
|
|
MachineFunction &MF = *MBB.getParent();
|
2016-07-28 18:40:00 +00:00
|
|
|
MachineFrameInfo &MFI = MF.getFrameInfo();
|
2020-03-31 09:43:50 +00:00
|
|
|
const Align Alignment = MFI.getObjectAlign(FI);
|
2015-08-11 23:09:45 +00:00
|
|
|
MachineMemOperand *MMO = MF.getMachineMemOperand(
|
|
|
|
MachinePointerInfo::getFixedStack(MF, FI), MachineMemOperand::MOLoad,
|
2020-03-31 09:43:50 +00:00
|
|
|
MFI.getObjectSize(FI), Alignment);
|
2009-07-08 16:09:28 +00:00
|
|
|
|
2017-04-24 18:55:33 +00:00
|
|
|
switch (TRI->getSpillSize(*RC)) {
|
2018-02-14 15:09:09 +00:00
|
|
|
case 2:
|
|
|
|
if (ARM::HPRRegClass.hasSubClassEq(RC)) {
|
|
|
|
BuildMI(MBB, I, DL, get(ARM::VLDRH), DestReg)
|
|
|
|
.addFrameIndex(FI)
|
|
|
|
.addImm(0)
|
|
|
|
.addMemOperand(MMO)
|
|
|
|
.add(predOps(ARMCC::AL));
|
|
|
|
} else
|
|
|
|
llvm_unreachable("Unknown reg class!");
|
|
|
|
break;
|
2011-08-10 17:21:20 +00:00
|
|
|
case 4:
|
|
|
|
if (ARM::GPRRegClass.hasSubClassEq(RC)) {
|
2017-01-13 09:37:56 +00:00
|
|
|
BuildMI(MBB, I, DL, get(ARM::LDRi12), DestReg)
|
|
|
|
.addFrameIndex(FI)
|
|
|
|
.addImm(0)
|
|
|
|
.addMemOperand(MMO)
|
|
|
|
.add(predOps(ARMCC::AL));
|
2011-08-10 17:21:20 +00:00
|
|
|
} else if (ARM::SPRRegClass.hasSubClassEq(RC)) {
|
2017-01-13 09:37:56 +00:00
|
|
|
BuildMI(MBB, I, DL, get(ARM::VLDRS), DestReg)
|
|
|
|
.addFrameIndex(FI)
|
|
|
|
.addImm(0)
|
|
|
|
.addMemOperand(MMO)
|
|
|
|
.add(predOps(ARMCC::AL));
|
[ARM] Code-generation infrastructure for MVE.
This provides the low-level support to start using MVE vector types in
LLVM IR, loading and storing them, passing them to __asm__ statements
containing hand-written MVE vector instructions, and *if* you have the
hard-float ABI turned on, using them as function parameters.
(In the soft-float ABI, vector types are passed in integer registers,
and combining all those 32-bit integers into a q-reg requires support
for selection DAG nodes like insert_vector_elt and build_vector which
aren't implemented yet for MVE. In fact I've also had to add
`arm_aapcs_vfpcc` to a couple of existing tests to avoid that
problem.)
Specifically, this commit adds support for:
* spills, reloads and register moves for MVE vector registers
* ditto for the VPT predication mask that lives in VPR.P0
* make all the MVE vector types legal in ISel, and provide selection
DAG patterns for BITCAST, LOAD and STORE
* make loads and stores of scalar FP types conditional on
`hasFPRegs()` rather than `hasVFP2Base()`. As a result a few
existing tests needed their llc command lines updating to use
`-mattr=-fpregs` as their method of turning off all hardware FP
support.
Reviewers: dmgreen, samparker, SjoerdMeijer
Subscribers: javed.absar, kristof.beyls, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60708
llvm-svn: 364329
2019-06-25 16:48:46 +00:00
|
|
|
} else if (ARM::VCCRRegClass.hasSubClassEq(RC)) {
|
|
|
|
BuildMI(MBB, I, DL, get(ARM::VLDR_P0_off), DestReg)
|
|
|
|
.addFrameIndex(FI)
|
|
|
|
.addImm(0)
|
|
|
|
.addMemOperand(MMO)
|
|
|
|
.add(predOps(ARMCC::AL));
|
2011-08-10 17:21:20 +00:00
|
|
|
} else
|
|
|
|
llvm_unreachable("Unknown reg class!");
|
2010-06-18 21:32:42 +00:00
|
|
|
break;
|
2011-08-10 17:21:20 +00:00
|
|
|
case 8:
|
|
|
|
if (ARM::DPRRegClass.hasSubClassEq(RC)) {
|
2017-01-13 09:37:56 +00:00
|
|
|
BuildMI(MBB, I, DL, get(ARM::VLDRD), DestReg)
|
|
|
|
.addFrameIndex(FI)
|
|
|
|
.addImm(0)
|
|
|
|
.addMemOperand(MMO)
|
|
|
|
.add(predOps(ARMCC::AL));
|
2012-10-26 21:29:15 +00:00
|
|
|
} else if (ARM::GPRPairRegClass.hasSubClassEq(RC)) {
|
2013-04-21 11:57:07 +00:00
|
|
|
MachineInstrBuilder MIB;
|
|
|
|
|
|
|
|
if (Subtarget.hasV5TEOps()) {
|
|
|
|
MIB = BuildMI(MBB, I, DL, get(ARM::LDRD));
|
|
|
|
AddDReg(MIB, DestReg, ARM::gsub_0, RegState::DefineNoRead, TRI);
|
|
|
|
AddDReg(MIB, DestReg, ARM::gsub_1, RegState::DefineNoRead, TRI);
|
2017-01-13 09:37:56 +00:00
|
|
|
MIB.addFrameIndex(FI).addReg(0).addImm(0).addMemOperand(MMO)
|
|
|
|
.add(predOps(ARMCC::AL));
|
2013-04-21 11:57:07 +00:00
|
|
|
} else {
|
|
|
|
// Fallback to LDM instruction, which has existed since the dawn of
|
|
|
|
// time.
|
2017-01-13 09:37:56 +00:00
|
|
|
MIB = BuildMI(MBB, I, DL, get(ARM::LDMIA))
|
|
|
|
.addFrameIndex(FI)
|
|
|
|
.addMemOperand(MMO)
|
|
|
|
.add(predOps(ARMCC::AL));
|
2013-04-21 11:57:07 +00:00
|
|
|
MIB = AddDReg(MIB, DestReg, ARM::gsub_0, RegState::DefineNoRead, TRI);
|
|
|
|
MIB = AddDReg(MIB, DestReg, ARM::gsub_1, RegState::DefineNoRead, TRI);
|
|
|
|
}
|
|
|
|
|
2019-08-01 23:27:28 +00:00
|
|
|
if (Register::isPhysicalRegister(DestReg))
|
2012-10-26 21:29:15 +00:00
|
|
|
MIB.addReg(DestReg, RegState::ImplicitDefine);
|
2011-08-10 17:21:20 +00:00
|
|
|
} else
|
|
|
|
llvm_unreachable("Unknown reg class!");
|
2010-06-18 21:32:42 +00:00
|
|
|
break;
|
2011-08-10 17:21:20 +00:00
|
|
|
case 16:
|
[ARM] Code-generation infrastructure for MVE.
This provides the low-level support to start using MVE vector types in
LLVM IR, loading and storing them, passing them to __asm__ statements
containing hand-written MVE vector instructions, and *if* you have the
hard-float ABI turned on, using them as function parameters.
(In the soft-float ABI, vector types are passed in integer registers,
and combining all those 32-bit integers into a q-reg requires support
for selection DAG nodes like insert_vector_elt and build_vector which
aren't implemented yet for MVE. In fact I've also had to add
`arm_aapcs_vfpcc` to a couple of existing tests to avoid that
problem.)
Specifically, this commit adds support for:
* spills, reloads and register moves for MVE vector registers
* ditto for the VPT predication mask that lives in VPR.P0
* make all the MVE vector types legal in ISel, and provide selection
DAG patterns for BITCAST, LOAD and STORE
* make loads and stores of scalar FP types conditional on
`hasFPRegs()` rather than `hasVFP2Base()`. As a result a few
existing tests needed their llc command lines updating to use
`-mattr=-fpregs` as their method of turning off all hardware FP
support.
Reviewers: dmgreen, samparker, SjoerdMeijer
Subscribers: javed.absar, kristof.beyls, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60708
llvm-svn: 364329
2019-06-25 16:48:46 +00:00
|
|
|
if (ARM::DPairRegClass.hasSubClassEq(RC) && Subtarget.hasNEON()) {
|
2020-03-31 09:43:50 +00:00
|
|
|
if (Alignment >= 16 && getRegisterInfo().canRealignStack(MF)) {
|
2017-01-13 09:37:56 +00:00
|
|
|
BuildMI(MBB, I, DL, get(ARM::VLD1q64), DestReg)
|
|
|
|
.addFrameIndex(FI)
|
|
|
|
.addImm(16)
|
|
|
|
.addMemOperand(MMO)
|
|
|
|
.add(predOps(ARMCC::AL));
|
2011-08-10 17:21:20 +00:00
|
|
|
} else {
|
2017-01-13 09:37:56 +00:00
|
|
|
BuildMI(MBB, I, DL, get(ARM::VLDMQIA), DestReg)
|
|
|
|
.addFrameIndex(FI)
|
|
|
|
.addMemOperand(MMO)
|
|
|
|
.add(predOps(ARMCC::AL));
|
2011-08-10 17:21:20 +00:00
|
|
|
}
|
[ARM] Code-generation infrastructure for MVE.
This provides the low-level support to start using MVE vector types in
LLVM IR, loading and storing them, passing them to __asm__ statements
containing hand-written MVE vector instructions, and *if* you have the
hard-float ABI turned on, using them as function parameters.
(In the soft-float ABI, vector types are passed in integer registers,
and combining all those 32-bit integers into a q-reg requires support
for selection DAG nodes like insert_vector_elt and build_vector which
aren't implemented yet for MVE. In fact I've also had to add
`arm_aapcs_vfpcc` to a couple of existing tests to avoid that
problem.)
Specifically, this commit adds support for:
* spills, reloads and register moves for MVE vector registers
* ditto for the VPT predication mask that lives in VPR.P0
* make all the MVE vector types legal in ISel, and provide selection
DAG patterns for BITCAST, LOAD and STORE
* make loads and stores of scalar FP types conditional on
`hasFPRegs()` rather than `hasVFP2Base()`. As a result a few
existing tests needed their llc command lines updating to use
`-mattr=-fpregs` as their method of turning off all hardware FP
support.
Reviewers: dmgreen, samparker, SjoerdMeijer
Subscribers: javed.absar, kristof.beyls, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60708
llvm-svn: 364329
2019-06-25 16:48:46 +00:00
|
|
|
} else if (ARM::QPRRegClass.hasSubClassEq(RC) &&
|
|
|
|
Subtarget.hasMVEIntegerOps()) {
|
|
|
|
auto MIB = BuildMI(MBB, I, DL, get(ARM::MVE_VLDRWU32), DestReg);
|
|
|
|
MIB.addFrameIndex(FI)
|
|
|
|
.addImm(0)
|
|
|
|
.addMemOperand(MMO);
|
|
|
|
addUnpredicatedMveVpredNOp(MIB);
|
2011-08-10 17:21:20 +00:00
|
|
|
} else
|
|
|
|
llvm_unreachable("Unknown reg class!");
|
2010-06-18 21:32:42 +00:00
|
|
|
break;
|
2012-08-04 13:16:12 +00:00
|
|
|
case 24:
|
|
|
|
if (ARM::DTripleRegClass.hasSubClassEq(RC)) {
|
2020-03-31 09:43:50 +00:00
|
|
|
if (Alignment >= 16 && getRegisterInfo().canRealignStack(MF) &&
|
2019-09-09 10:46:25 +00:00
|
|
|
Subtarget.hasNEON()) {
|
2017-01-13 09:37:56 +00:00
|
|
|
BuildMI(MBB, I, DL, get(ARM::VLD1d64TPseudo), DestReg)
|
|
|
|
.addFrameIndex(FI)
|
|
|
|
.addImm(16)
|
|
|
|
.addMemOperand(MMO)
|
|
|
|
.add(predOps(ARMCC::AL));
|
2012-08-04 13:16:12 +00:00
|
|
|
} else {
|
2017-01-13 09:37:56 +00:00
|
|
|
MachineInstrBuilder MIB = BuildMI(MBB, I, DL, get(ARM::VLDMDIA))
|
|
|
|
.addFrameIndex(FI)
|
|
|
|
.addMemOperand(MMO)
|
|
|
|
.add(predOps(ARMCC::AL));
|
2012-08-04 13:16:12 +00:00
|
|
|
MIB = AddDReg(MIB, DestReg, ARM::dsub_0, RegState::DefineNoRead, TRI);
|
|
|
|
MIB = AddDReg(MIB, DestReg, ARM::dsub_1, RegState::DefineNoRead, TRI);
|
|
|
|
MIB = AddDReg(MIB, DestReg, ARM::dsub_2, RegState::DefineNoRead, TRI);
|
2019-08-01 23:27:28 +00:00
|
|
|
if (Register::isPhysicalRegister(DestReg))
|
2012-08-04 13:16:12 +00:00
|
|
|
MIB.addReg(DestReg, RegState::ImplicitDefine);
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
llvm_unreachable("Unknown reg class!");
|
|
|
|
break;
|
|
|
|
case 32:
|
|
|
|
if (ARM::QQPRRegClass.hasSubClassEq(RC) || ARM::DQuadRegClass.hasSubClassEq(RC)) {
|
2020-03-31 09:43:50 +00:00
|
|
|
if (Alignment >= 16 && getRegisterInfo().canRealignStack(MF) &&
|
2019-09-09 10:46:25 +00:00
|
|
|
Subtarget.hasNEON()) {
|
2017-01-13 09:37:56 +00:00
|
|
|
BuildMI(MBB, I, DL, get(ARM::VLD1d64QPseudo), DestReg)
|
|
|
|
.addFrameIndex(FI)
|
|
|
|
.addImm(16)
|
|
|
|
.addMemOperand(MMO)
|
|
|
|
.add(predOps(ARMCC::AL));
|
2011-08-10 17:21:20 +00:00
|
|
|
} else {
|
2017-01-13 09:37:56 +00:00
|
|
|
MachineInstrBuilder MIB = BuildMI(MBB, I, DL, get(ARM::VLDMDIA))
|
|
|
|
.addFrameIndex(FI)
|
|
|
|
.add(predOps(ARMCC::AL))
|
|
|
|
.addMemOperand(MMO);
|
2012-03-04 18:40:30 +00:00
|
|
|
MIB = AddDReg(MIB, DestReg, ARM::dsub_0, RegState::DefineNoRead, TRI);
|
|
|
|
MIB = AddDReg(MIB, DestReg, ARM::dsub_1, RegState::DefineNoRead, TRI);
|
|
|
|
MIB = AddDReg(MIB, DestReg, ARM::dsub_2, RegState::DefineNoRead, TRI);
|
|
|
|
MIB = AddDReg(MIB, DestReg, ARM::dsub_3, RegState::DefineNoRead, TRI);
|
2019-08-01 23:27:28 +00:00
|
|
|
if (Register::isPhysicalRegister(DestReg))
|
2012-03-06 02:48:17 +00:00
|
|
|
MIB.addReg(DestReg, RegState::ImplicitDefine);
|
2011-08-10 17:21:20 +00:00
|
|
|
}
|
|
|
|
} else
|
|
|
|
llvm_unreachable("Unknown reg class!");
|
2010-06-18 21:32:42 +00:00
|
|
|
break;
|
2011-08-10 17:21:20 +00:00
|
|
|
case 64:
|
|
|
|
if (ARM::QQQQPRRegClass.hasSubClassEq(RC)) {
|
2017-01-13 09:37:56 +00:00
|
|
|
MachineInstrBuilder MIB = BuildMI(MBB, I, DL, get(ARM::VLDMDIA))
|
|
|
|
.addFrameIndex(FI)
|
|
|
|
.add(predOps(ARMCC::AL))
|
|
|
|
.addMemOperand(MMO);
|
2012-03-04 18:40:30 +00:00
|
|
|
MIB = AddDReg(MIB, DestReg, ARM::dsub_0, RegState::DefineNoRead, TRI);
|
|
|
|
MIB = AddDReg(MIB, DestReg, ARM::dsub_1, RegState::DefineNoRead, TRI);
|
|
|
|
MIB = AddDReg(MIB, DestReg, ARM::dsub_2, RegState::DefineNoRead, TRI);
|
|
|
|
MIB = AddDReg(MIB, DestReg, ARM::dsub_3, RegState::DefineNoRead, TRI);
|
|
|
|
MIB = AddDReg(MIB, DestReg, ARM::dsub_4, RegState::DefineNoRead, TRI);
|
|
|
|
MIB = AddDReg(MIB, DestReg, ARM::dsub_5, RegState::DefineNoRead, TRI);
|
|
|
|
MIB = AddDReg(MIB, DestReg, ARM::dsub_6, RegState::DefineNoRead, TRI);
|
|
|
|
MIB = AddDReg(MIB, DestReg, ARM::dsub_7, RegState::DefineNoRead, TRI);
|
2019-08-01 23:27:28 +00:00
|
|
|
if (Register::isPhysicalRegister(DestReg))
|
2012-03-06 02:48:17 +00:00
|
|
|
MIB.addReg(DestReg, RegState::ImplicitDefine);
|
2011-08-10 17:21:20 +00:00
|
|
|
} else
|
|
|
|
llvm_unreachable("Unknown reg class!");
|
2010-06-18 21:32:42 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
llvm_unreachable("Unknown regclass!");
|
2009-07-08 16:09:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
unsigned ARMBaseInstrInfo::isLoadFromStackSlot(const MachineInstr &MI,
|
|
|
|
int &FrameIndex) const {
|
|
|
|
switch (MI.getOpcode()) {
|
2010-09-15 16:36:26 +00:00
|
|
|
default: break;
|
2010-10-26 22:37:02 +00:00
|
|
|
case ARM::LDRrs:
|
2010-09-15 16:36:26 +00:00
|
|
|
case ARM::t2LDRs: // FIXME: don't use t2LDRs to access frame.
|
2016-06-30 00:01:54 +00:00
|
|
|
if (MI.getOperand(1).isFI() && MI.getOperand(2).isReg() &&
|
|
|
|
MI.getOperand(3).isImm() && MI.getOperand(2).getReg() == 0 &&
|
|
|
|
MI.getOperand(3).getImm() == 0) {
|
|
|
|
FrameIndex = MI.getOperand(1).getIndex();
|
|
|
|
return MI.getOperand(0).getReg();
|
2010-09-15 16:36:26 +00:00
|
|
|
}
|
|
|
|
break;
|
2010-10-26 22:37:02 +00:00
|
|
|
case ARM::LDRi12:
|
2010-09-15 16:36:26 +00:00
|
|
|
case ARM::t2LDRi12:
|
2011-06-29 20:26:39 +00:00
|
|
|
case ARM::tLDRspi:
|
2010-09-15 16:36:26 +00:00
|
|
|
case ARM::VLDRD:
|
|
|
|
case ARM::VLDRS:
|
2016-06-30 00:01:54 +00:00
|
|
|
if (MI.getOperand(1).isFI() && MI.getOperand(2).isImm() &&
|
|
|
|
MI.getOperand(2).getImm() == 0) {
|
|
|
|
FrameIndex = MI.getOperand(1).getIndex();
|
|
|
|
return MI.getOperand(0).getReg();
|
2010-09-15 17:27:09 +00:00
|
|
|
}
|
|
|
|
break;
|
[ARM] Code-generation infrastructure for MVE.
This provides the low-level support to start using MVE vector types in
LLVM IR, loading and storing them, passing them to __asm__ statements
containing hand-written MVE vector instructions, and *if* you have the
hard-float ABI turned on, using them as function parameters.
(In the soft-float ABI, vector types are passed in integer registers,
and combining all those 32-bit integers into a q-reg requires support
for selection DAG nodes like insert_vector_elt and build_vector which
aren't implemented yet for MVE. In fact I've also had to add
`arm_aapcs_vfpcc` to a couple of existing tests to avoid that
problem.)
Specifically, this commit adds support for:
* spills, reloads and register moves for MVE vector registers
* ditto for the VPT predication mask that lives in VPR.P0
* make all the MVE vector types legal in ISel, and provide selection
DAG patterns for BITCAST, LOAD and STORE
* make loads and stores of scalar FP types conditional on
`hasFPRegs()` rather than `hasVFP2Base()`. As a result a few
existing tests needed their llc command lines updating to use
`-mattr=-fpregs` as their method of turning off all hardware FP
support.
Reviewers: dmgreen, samparker, SjoerdMeijer
Subscribers: javed.absar, kristof.beyls, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60708
llvm-svn: 364329
2019-06-25 16:48:46 +00:00
|
|
|
case ARM::VLDR_P0_off:
|
|
|
|
if (MI.getOperand(0).isFI() && MI.getOperand(1).isImm() &&
|
|
|
|
MI.getOperand(1).getImm() == 0) {
|
|
|
|
FrameIndex = MI.getOperand(0).getIndex();
|
|
|
|
return ARM::P0;
|
|
|
|
}
|
|
|
|
break;
|
2012-03-05 19:33:30 +00:00
|
|
|
case ARM::VLD1q64:
|
2018-06-02 16:40:03 +00:00
|
|
|
case ARM::VLD1d8TPseudo:
|
|
|
|
case ARM::VLD1d16TPseudo:
|
|
|
|
case ARM::VLD1d32TPseudo:
|
2012-08-04 13:22:14 +00:00
|
|
|
case ARM::VLD1d64TPseudo:
|
2018-06-02 16:40:03 +00:00
|
|
|
case ARM::VLD1d8QPseudo:
|
|
|
|
case ARM::VLD1d16QPseudo:
|
|
|
|
case ARM::VLD1d32QPseudo:
|
2012-08-04 13:22:14 +00:00
|
|
|
case ARM::VLD1d64QPseudo:
|
2016-06-30 00:01:54 +00:00
|
|
|
if (MI.getOperand(1).isFI() && MI.getOperand(0).getSubReg() == 0) {
|
|
|
|
FrameIndex = MI.getOperand(1).getIndex();
|
|
|
|
return MI.getOperand(0).getReg();
|
2010-09-15 21:40:11 +00:00
|
|
|
}
|
|
|
|
break;
|
2010-11-16 01:16:36 +00:00
|
|
|
case ARM::VLDMQIA:
|
2016-06-30 00:01:54 +00:00
|
|
|
if (MI.getOperand(1).isFI() && MI.getOperand(0).getSubReg() == 0) {
|
|
|
|
FrameIndex = MI.getOperand(1).getIndex();
|
|
|
|
return MI.getOperand(0).getReg();
|
2010-09-15 16:36:26 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
unsigned ARMBaseInstrInfo::isLoadFromStackSlotPostFE(const MachineInstr &MI,
|
|
|
|
int &FrameIndex) const {
|
2018-09-05 08:59:50 +00:00
|
|
|
SmallVector<const MachineMemOperand *, 1> Accesses;
|
2019-03-25 22:42:30 +00:00
|
|
|
if (MI.mayLoad() && hasLoadFromStackSlot(MI, Accesses) &&
|
|
|
|
Accesses.size() == 1) {
|
2018-09-05 08:59:50 +00:00
|
|
|
FrameIndex =
|
|
|
|
cast<FixedStackPseudoSourceValue>(Accesses.front()->getPseudoValue())
|
|
|
|
->getFrameIndex();
|
2018-09-03 09:15:58 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2011-08-08 21:45:32 +00:00
|
|
|
}
|
|
|
|
|
2018-05-01 15:54:18 +00:00
|
|
|
/// Expands MEMCPY to either LDMIA/STMIA or LDMIA_UPD/STMID_UPD
|
2015-10-05 14:49:54 +00:00
|
|
|
/// depending on whether the result is used.
|
2016-07-08 20:21:17 +00:00
|
|
|
void ARMBaseInstrInfo::expandMEMCPY(MachineBasicBlock::iterator MI) const {
|
2015-10-05 14:49:54 +00:00
|
|
|
bool isThumb1 = Subtarget.isThumb1Only();
|
|
|
|
bool isThumb2 = Subtarget.isThumb2();
|
|
|
|
const ARMBaseInstrInfo *TII = Subtarget.getInstrInfo();
|
|
|
|
|
|
|
|
DebugLoc dl = MI->getDebugLoc();
|
|
|
|
MachineBasicBlock *BB = MI->getParent();
|
|
|
|
|
|
|
|
MachineInstrBuilder LDM, STM;
|
|
|
|
if (isThumb1 || !MI->getOperand(1).isDead()) {
|
2017-12-12 17:53:59 +00:00
|
|
|
MachineOperand LDWb(MI->getOperand(1));
|
2015-10-05 14:49:54 +00:00
|
|
|
LDM = BuildMI(*BB, MI, dl, TII->get(isThumb2 ? ARM::t2LDMIA_UPD
|
|
|
|
: isThumb1 ? ARM::tLDMIA_UPD
|
|
|
|
: ARM::LDMIA_UPD))
|
2017-12-12 17:53:59 +00:00
|
|
|
.add(LDWb);
|
2015-10-05 14:49:54 +00:00
|
|
|
} else {
|
|
|
|
LDM = BuildMI(*BB, MI, dl, TII->get(isThumb2 ? ARM::t2LDMIA : ARM::LDMIA));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isThumb1 || !MI->getOperand(0).isDead()) {
|
2017-12-12 17:53:59 +00:00
|
|
|
MachineOperand STWb(MI->getOperand(0));
|
2015-10-05 14:49:54 +00:00
|
|
|
STM = BuildMI(*BB, MI, dl, TII->get(isThumb2 ? ARM::t2STMIA_UPD
|
|
|
|
: isThumb1 ? ARM::tSTMIA_UPD
|
|
|
|
: ARM::STMIA_UPD))
|
2017-12-12 17:53:59 +00:00
|
|
|
.add(STWb);
|
2015-10-05 14:49:54 +00:00
|
|
|
} else {
|
|
|
|
STM = BuildMI(*BB, MI, dl, TII->get(isThumb2 ? ARM::t2STMIA : ARM::STMIA));
|
|
|
|
}
|
|
|
|
|
2017-12-12 17:53:59 +00:00
|
|
|
MachineOperand LDBase(MI->getOperand(3));
|
|
|
|
LDM.add(LDBase).add(predOps(ARMCC::AL));
|
|
|
|
|
|
|
|
MachineOperand STBase(MI->getOperand(2));
|
|
|
|
STM.add(STBase).add(predOps(ARMCC::AL));
|
2015-10-05 14:49:54 +00:00
|
|
|
|
|
|
|
// Sort the scratch registers into ascending order.
|
|
|
|
const TargetRegisterInfo &TRI = getRegisterInfo();
|
2017-01-26 23:40:06 +00:00
|
|
|
SmallVector<unsigned, 6> ScratchRegs;
|
2015-10-05 14:49:54 +00:00
|
|
|
for(unsigned I = 5; I < MI->getNumOperands(); ++I)
|
|
|
|
ScratchRegs.push_back(MI->getOperand(I).getReg());
|
llvm::sort(C.begin(), C.end(), ...) -> llvm::sort(C, ...)
Summary: The convenience wrapper in STLExtras is available since rL342102.
Reviewers: dblaikie, javed.absar, JDevlieghere, andreadb
Subscribers: MatzeB, sanjoy, arsenm, dschuff, mehdi_amini, sdardis, nemanjai, jvesely, nhaehnle, sbc100, jgravelle-google, eraman, aheejin, kbarton, JDevlieghere, javed.absar, gbedwell, jrtc27, mgrang, atanasyan, steven_wu, george.burgess.iv, dexonsmith, kristina, jsji, llvm-commits
Differential Revision: https://reviews.llvm.org/D52573
llvm-svn: 343163
2018-09-27 02:13:45 +00:00
|
|
|
llvm::sort(ScratchRegs,
|
|
|
|
[&TRI](const unsigned &Reg1, const unsigned &Reg2) -> bool {
|
2018-04-05 18:31:50 +00:00
|
|
|
return TRI.getEncodingValue(Reg1) <
|
|
|
|
TRI.getEncodingValue(Reg2);
|
|
|
|
});
|
2015-10-05 14:49:54 +00:00
|
|
|
|
|
|
|
for (const auto &Reg : ScratchRegs) {
|
|
|
|
LDM.addReg(Reg, RegState::Define);
|
|
|
|
STM.addReg(Reg, RegState::Kill);
|
|
|
|
}
|
|
|
|
|
2016-07-08 20:21:17 +00:00
|
|
|
BB->erase(MI);
|
2015-10-05 14:49:54 +00:00
|
|
|
}
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
bool ARMBaseInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
|
|
|
|
if (MI.getOpcode() == TargetOpcode::LOAD_STACK_GUARD) {
|
2015-07-06 16:33:18 +00:00
|
|
|
assert(getSubtarget().getTargetTriple().isOSBinFormatMachO() &&
|
2014-07-25 19:31:34 +00:00
|
|
|
"LOAD_STACK_GUARD currently supported only for MachO.");
|
2016-06-28 15:18:26 +00:00
|
|
|
expandLoadStackGuard(MI);
|
2016-06-30 00:01:54 +00:00
|
|
|
MI.getParent()->erase(MI);
|
2014-07-25 19:31:34 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
if (MI.getOpcode() == ARM::MEMCPY) {
|
2015-10-05 14:49:54 +00:00
|
|
|
expandMEMCPY(MI);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-10-11 00:59:06 +00:00
|
|
|
// This hook gets to expand COPY instructions before they become
|
|
|
|
// copyPhysReg() calls. Look for VMOVS instructions that can legally be
|
|
|
|
// widened to VMOVD. We prefer the VMOVD when possible because it may be
|
|
|
|
// changed into a VORR that can go down the NEON pipeline.
|
[ARM] Replace fp-only-sp and d16 with fp64 and d32.
Those two subtarget features were awkward because their semantics are
reversed: each one indicates the _lack_ of support for something in
the architecture, rather than the presence. As a consequence, you
don't get the behavior you want if you combine two sets of feature
bits.
Each SubtargetFeature for an FP architecture version now comes in four
versions, one for each combination of those options. So you can still
say (for example) '+vfp2' in a feature string and it will mean what
it's always meant, but there's a new string '+vfp2d16sp' meaning the
version without those extra options.
A lot of this change is just mechanically replacing positive checks
for the old features with negative checks for the new ones. But one
more interesting change is that I've rearranged getFPUFeatures() so
that the main FPU feature is appended to the output list *before*
rather than after the features derived from the Restriction field, so
that -fp64 and -d32 can override defaults added by the main feature.
Reviewers: dmgreen, samparker, SjoerdMeijer
Subscribers: srhines, javed.absar, eraman, kristof.beyls, hiraditya, zzheng, Petar.Avramovic, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D60691
llvm-svn: 361845
2019-05-28 16:13:20 +00:00
|
|
|
if (!MI.isCopy() || Subtarget.dontWidenVMOVS() || !Subtarget.hasFP64())
|
2011-10-11 00:59:06 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// Look for a copy between even S-registers. That is where we keep floats
|
|
|
|
// when using NEON v2f32 instructions for f32 arithmetic.
|
Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Partial reverts in:
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
X86FixupLEAs.cpp - Some functions return unsigned and arguably should be MCRegister
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
HexagonBitSimplify.cpp - Function takes BitTracker::RegisterRef which appears to be unsigned&
MachineVerifier.cpp - Ambiguous operator==() given MCRegister and const Register
PPCFastISel.cpp - No Register::operator-=()
PeepholeOptimizer.cpp - TargetInstrInfo::optimizeLoadInstr() takes an unsigned&
MachineTraceMetrics.cpp - MachineTraceMetrics lacks a suitable constructor
Manual fixups in:
ARMFastISel.cpp - ARMEmitLoad() now takes a Register& instead of unsigned&
HexagonSplitDouble.cpp - Ternary operator was ambiguous between unsigned/Register
HexagonConstExtenders.cpp - Has a local class named Register, used llvm::Register instead of Register.
PPCFastISel.cpp - PPCEmitLoad() now takes a Register& instead of unsigned&
Depends on D65919
Reviewers: arsenm, bogner, craig.topper, RKSimon
Reviewed By: arsenm
Subscribers: RKSimon, craig.topper, lenary, aemerson, wuzish, jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65962
llvm-svn: 369041
2019-08-15 19:22:08 +00:00
|
|
|
Register DstRegS = MI.getOperand(0).getReg();
|
|
|
|
Register SrcRegS = MI.getOperand(1).getReg();
|
2011-10-11 00:59:06 +00:00
|
|
|
if (!ARM::SPRRegClass.contains(DstRegS, SrcRegS))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
const TargetRegisterInfo *TRI = &getRegisterInfo();
|
|
|
|
unsigned DstRegD = TRI->getMatchingSuperReg(DstRegS, ARM::ssub_0,
|
|
|
|
&ARM::DPRRegClass);
|
|
|
|
unsigned SrcRegD = TRI->getMatchingSuperReg(SrcRegS, ARM::ssub_0,
|
|
|
|
&ARM::DPRRegClass);
|
|
|
|
if (!DstRegD || !SrcRegD)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// We want to widen this into a DstRegD = VMOVD SrcRegD copy. This is only
|
|
|
|
// legal if the COPY already defines the full DstRegD, and it isn't a
|
|
|
|
// sub-register insertion.
|
2016-06-30 00:01:54 +00:00
|
|
|
if (!MI.definesRegister(DstRegD, TRI) || MI.readsRegister(DstRegD, TRI))
|
2011-10-11 00:59:06 +00:00
|
|
|
return false;
|
|
|
|
|
2011-10-12 00:06:23 +00:00
|
|
|
// A dead copy shouldn't show up here, but reject it just in case.
|
2016-06-30 00:01:54 +00:00
|
|
|
if (MI.getOperand(0).isDead())
|
2011-10-12 00:06:23 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// All clear, widen the COPY.
|
2018-05-14 12:53:11 +00:00
|
|
|
LLVM_DEBUG(dbgs() << "widening: " << MI);
|
2016-06-30 00:01:54 +00:00
|
|
|
MachineInstrBuilder MIB(*MI.getParent()->getParent(), MI);
|
2011-10-12 00:06:23 +00:00
|
|
|
|
2017-12-07 10:40:31 +00:00
|
|
|
// Get rid of the old implicit-def of DstRegD. Leave it if it defines a Q-reg
|
2011-10-12 00:06:23 +00:00
|
|
|
// or some other super-register.
|
2016-06-30 00:01:54 +00:00
|
|
|
int ImpDefIdx = MI.findRegisterDefOperandIdx(DstRegD);
|
2011-10-12 00:06:23 +00:00
|
|
|
if (ImpDefIdx != -1)
|
2016-06-30 00:01:54 +00:00
|
|
|
MI.RemoveOperand(ImpDefIdx);
|
2011-10-12 00:06:23 +00:00
|
|
|
|
|
|
|
// Change the opcode and operands.
|
2016-06-30 00:01:54 +00:00
|
|
|
MI.setDesc(get(ARM::VMOVD));
|
|
|
|
MI.getOperand(0).setReg(DstRegD);
|
|
|
|
MI.getOperand(1).setReg(SrcRegD);
|
2017-01-13 09:37:56 +00:00
|
|
|
MIB.add(predOps(ARMCC::AL));
|
2011-10-12 00:06:23 +00:00
|
|
|
|
|
|
|
// We are now reading SrcRegD instead of SrcRegS. This may upset the
|
|
|
|
// register scavenger and machine verifier, so we need to indicate that we
|
|
|
|
// are reading an undefined value from SrcRegD, but a proper value from
|
|
|
|
// SrcRegS.
|
2016-06-30 00:01:54 +00:00
|
|
|
MI.getOperand(1).setIsUndef();
|
2012-12-19 21:31:56 +00:00
|
|
|
MIB.addReg(SrcRegS, RegState::Implicit);
|
2011-10-12 00:06:23 +00:00
|
|
|
|
|
|
|
// SrcRegD may actually contain an unrelated value in the ssub_1
|
|
|
|
// sub-register. Don't kill it. Only kill the ssub_0 sub-register.
|
2016-06-30 00:01:54 +00:00
|
|
|
if (MI.getOperand(1).isKill()) {
|
|
|
|
MI.getOperand(1).setIsKill(false);
|
|
|
|
MI.addRegisterKilled(SrcRegS, TRI, true);
|
2011-10-12 00:06:23 +00:00
|
|
|
}
|
|
|
|
|
2018-05-14 12:53:11 +00:00
|
|
|
LLVM_DEBUG(dbgs() << "replaced by: " << MI);
|
2011-10-11 00:59:06 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-01-06 23:47:07 +00:00
|
|
|
/// Create a copy of a const pool value. Update CPI to the new index and return
|
|
|
|
/// the label UID.
|
|
|
|
static unsigned duplicateCPV(MachineFunction &MF, unsigned &CPI) {
|
|
|
|
MachineConstantPool *MCP = MF.getConstantPool();
|
|
|
|
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
|
|
|
|
|
|
|
|
const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPI];
|
|
|
|
assert(MCPE.isMachineConstantPoolEntry() &&
|
|
|
|
"Expecting a machine constantpool entry!");
|
|
|
|
ARMConstantPoolValue *ACPV =
|
|
|
|
static_cast<ARMConstantPoolValue*>(MCPE.Val.MachineCPVal);
|
|
|
|
|
2011-01-17 08:03:18 +00:00
|
|
|
unsigned PCLabelId = AFI->createPICLabelUId();
|
2014-04-25 05:30:21 +00:00
|
|
|
ARMConstantPoolValue *NewCPV = nullptr;
|
2014-01-29 16:01:24 +00:00
|
|
|
|
2010-09-10 21:38:22 +00:00
|
|
|
// FIXME: The below assumes PIC relocation model and that the function
|
|
|
|
// is Thumb mode (t1 or t2). PCAdjustment would be 8 for ARM mode PIC, and
|
|
|
|
// zero for non-PIC in ARM or Thumb. The callers are all of thumb LDR
|
|
|
|
// instructions, so that's probably OK, but is PIC always correct when
|
|
|
|
// we get here?
|
2010-01-06 23:47:07 +00:00
|
|
|
if (ACPV->isGlobalValue())
|
2015-10-26 18:23:16 +00:00
|
|
|
NewCPV = ARMConstantPoolConstant::Create(
|
|
|
|
cast<ARMConstantPoolConstant>(ACPV)->getGV(), PCLabelId, ARMCP::CPValue,
|
|
|
|
4, ACPV->getModifier(), ACPV->mustAddCurrentAddress());
|
2010-01-06 23:47:07 +00:00
|
|
|
else if (ACPV->isExtSymbol())
|
2011-10-01 08:58:29 +00:00
|
|
|
NewCPV = ARMConstantPoolSymbol::
|
2017-12-15 22:22:58 +00:00
|
|
|
Create(MF.getFunction().getContext(),
|
2011-10-01 08:58:29 +00:00
|
|
|
cast<ARMConstantPoolSymbol>(ACPV)->getSymbol(), PCLabelId, 4);
|
2010-01-06 23:47:07 +00:00
|
|
|
else if (ACPV->isBlockAddress())
|
2011-10-01 08:00:54 +00:00
|
|
|
NewCPV = ARMConstantPoolConstant::
|
|
|
|
Create(cast<ARMConstantPoolConstant>(ACPV)->getBlockAddress(), PCLabelId,
|
|
|
|
ARMCP::CPBlockAddress, 4);
|
2010-09-10 21:38:22 +00:00
|
|
|
else if (ACPV->isLSDA())
|
2017-12-15 22:22:58 +00:00
|
|
|
NewCPV = ARMConstantPoolConstant::Create(&MF.getFunction(), PCLabelId,
|
2011-10-01 08:00:54 +00:00
|
|
|
ARMCP::CPLSDA, 4);
|
2011-09-29 23:50:42 +00:00
|
|
|
else if (ACPV->isMachineBasicBlock())
|
2011-10-01 09:30:42 +00:00
|
|
|
NewCPV = ARMConstantPoolMBB::
|
2017-12-15 22:22:58 +00:00
|
|
|
Create(MF.getFunction().getContext(),
|
2011-10-01 09:30:42 +00:00
|
|
|
cast<ARMConstantPoolMBB>(ACPV)->getMBB(), PCLabelId, 4);
|
2010-01-06 23:47:07 +00:00
|
|
|
else
|
|
|
|
llvm_unreachable("Unexpected ARM constantpool value type!!");
|
2020-05-12 09:43:24 -07:00
|
|
|
CPI = MCP->getConstantPoolIndex(NewCPV, MCPE.getAlign());
|
2010-01-06 23:47:07 +00:00
|
|
|
return PCLabelId;
|
|
|
|
}
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
void ARMBaseInstrInfo::reMaterialize(MachineBasicBlock &MBB,
|
|
|
|
MachineBasicBlock::iterator I,
|
2020-04-03 13:22:51 -04:00
|
|
|
Register DestReg, unsigned SubIdx,
|
2016-06-30 00:01:54 +00:00
|
|
|
const MachineInstr &Orig,
|
|
|
|
const TargetRegisterInfo &TRI) const {
|
|
|
|
unsigned Opcode = Orig.getOpcode();
|
2009-11-08 00:15:23 +00:00
|
|
|
switch (Opcode) {
|
|
|
|
default: {
|
2016-06-30 00:01:54 +00:00
|
|
|
MachineInstr *MI = MBB.getParent()->CloneMachineInstr(&Orig);
|
|
|
|
MI->substituteRegister(Orig.getOperand(0).getReg(), DestReg, SubIdx, TRI);
|
2009-11-08 00:15:23 +00:00
|
|
|
MBB.insert(I, MI);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case ARM::tLDRpci_pic:
|
|
|
|
case ARM::t2LDRpci_pic: {
|
|
|
|
MachineFunction &MF = *MBB.getParent();
|
2016-06-30 00:01:54 +00:00
|
|
|
unsigned CPI = Orig.getOperand(1).getIndex();
|
2010-01-06 23:47:07 +00:00
|
|
|
unsigned PCLabelId = duplicateCPV(MF, CPI);
|
2018-08-16 21:30:05 +00:00
|
|
|
BuildMI(MBB, I, Orig.getDebugLoc(), get(Opcode), DestReg)
|
|
|
|
.addConstantPoolIndex(CPI)
|
|
|
|
.addImm(PCLabelId)
|
|
|
|
.cloneMemRefs(Orig);
|
2009-11-08 00:15:23 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-22 23:56:30 +00:00
|
|
|
MachineInstr &
|
|
|
|
ARMBaseInstrInfo::duplicate(MachineBasicBlock &MBB,
|
|
|
|
MachineBasicBlock::iterator InsertBefore,
|
|
|
|
const MachineInstr &Orig) const {
|
|
|
|
MachineInstr &Cloned = TargetInstrInfo::duplicate(MBB, InsertBefore, Orig);
|
|
|
|
MachineBasicBlock::instr_iterator I = Cloned.getIterator();
|
|
|
|
for (;;) {
|
|
|
|
switch (I->getOpcode()) {
|
|
|
|
case ARM::tLDRpci_pic:
|
|
|
|
case ARM::t2LDRpci_pic: {
|
|
|
|
MachineFunction &MF = *MBB.getParent();
|
|
|
|
unsigned CPI = I->getOperand(1).getIndex();
|
|
|
|
unsigned PCLabelId = duplicateCPV(MF, CPI);
|
|
|
|
I->getOperand(1).setIndex(CPI);
|
|
|
|
I->getOperand(2).setImm(PCLabelId);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!I->isBundledWithSucc())
|
|
|
|
break;
|
|
|
|
++I;
|
2010-01-06 23:47:07 +00:00
|
|
|
}
|
2017-08-22 23:56:30 +00:00
|
|
|
return Cloned;
|
2010-01-06 23:47:07 +00:00
|
|
|
}
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
bool ARMBaseInstrInfo::produceSameValue(const MachineInstr &MI0,
|
|
|
|
const MachineInstr &MI1,
|
2011-01-20 08:34:58 +00:00
|
|
|
const MachineRegisterInfo *MRI) const {
|
2016-06-30 00:01:54 +00:00
|
|
|
unsigned Opcode = MI0.getOpcode();
|
2011-01-20 23:55:07 +00:00
|
|
|
if (Opcode == ARM::t2LDRpci ||
|
2009-11-20 02:10:27 +00:00
|
|
|
Opcode == ARM::t2LDRpci_pic ||
|
|
|
|
Opcode == ARM::tLDRpci ||
|
2011-01-20 08:34:58 +00:00
|
|
|
Opcode == ARM::tLDRpci_pic ||
|
2013-12-02 10:35:41 +00:00
|
|
|
Opcode == ARM::LDRLIT_ga_pcrel ||
|
|
|
|
Opcode == ARM::LDRLIT_ga_pcrel_ldr ||
|
|
|
|
Opcode == ARM::tLDRLIT_ga_pcrel ||
|
2011-01-21 18:55:51 +00:00
|
|
|
Opcode == ARM::MOV_ga_pcrel ||
|
|
|
|
Opcode == ARM::MOV_ga_pcrel_ldr ||
|
|
|
|
Opcode == ARM::t2MOV_ga_pcrel) {
|
2016-06-30 00:01:54 +00:00
|
|
|
if (MI1.getOpcode() != Opcode)
|
2009-11-07 04:04:34 +00:00
|
|
|
return false;
|
2016-06-30 00:01:54 +00:00
|
|
|
if (MI0.getNumOperands() != MI1.getNumOperands())
|
2009-11-07 04:04:34 +00:00
|
|
|
return false;
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
const MachineOperand &MO0 = MI0.getOperand(1);
|
|
|
|
const MachineOperand &MO1 = MI1.getOperand(1);
|
2009-11-07 04:04:34 +00:00
|
|
|
if (MO0.getOffset() != MO1.getOffset())
|
|
|
|
return false;
|
|
|
|
|
2013-12-02 10:35:41 +00:00
|
|
|
if (Opcode == ARM::LDRLIT_ga_pcrel ||
|
|
|
|
Opcode == ARM::LDRLIT_ga_pcrel_ldr ||
|
|
|
|
Opcode == ARM::tLDRLIT_ga_pcrel ||
|
|
|
|
Opcode == ARM::MOV_ga_pcrel ||
|
2011-01-21 18:55:51 +00:00
|
|
|
Opcode == ARM::MOV_ga_pcrel_ldr ||
|
|
|
|
Opcode == ARM::t2MOV_ga_pcrel)
|
2011-01-20 08:34:58 +00:00
|
|
|
// Ignore the PC labels.
|
|
|
|
return MO0.getGlobal() == MO1.getGlobal();
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
const MachineFunction *MF = MI0.getParent()->getParent();
|
2009-11-07 04:04:34 +00:00
|
|
|
const MachineConstantPool *MCP = MF->getConstantPool();
|
|
|
|
int CPI0 = MO0.getIndex();
|
|
|
|
int CPI1 = MO1.getIndex();
|
|
|
|
const MachineConstantPoolEntry &MCPE0 = MCP->getConstants()[CPI0];
|
|
|
|
const MachineConstantPoolEntry &MCPE1 = MCP->getConstants()[CPI1];
|
2011-03-24 06:20:03 +00:00
|
|
|
bool isARMCP0 = MCPE0.isMachineConstantPoolEntry();
|
|
|
|
bool isARMCP1 = MCPE1.isMachineConstantPoolEntry();
|
|
|
|
if (isARMCP0 && isARMCP1) {
|
|
|
|
ARMConstantPoolValue *ACPV0 =
|
|
|
|
static_cast<ARMConstantPoolValue*>(MCPE0.Val.MachineCPVal);
|
|
|
|
ARMConstantPoolValue *ACPV1 =
|
|
|
|
static_cast<ARMConstantPoolValue*>(MCPE1.Val.MachineCPVal);
|
|
|
|
return ACPV0->hasSameValue(ACPV1);
|
|
|
|
} else if (!isARMCP0 && !isARMCP1) {
|
|
|
|
return MCPE0.Val.ConstVal == MCPE1.Val.ConstVal;
|
|
|
|
}
|
|
|
|
return false;
|
2011-01-20 08:34:58 +00:00
|
|
|
} else if (Opcode == ARM::PICLDR) {
|
2016-06-30 00:01:54 +00:00
|
|
|
if (MI1.getOpcode() != Opcode)
|
2011-01-20 08:34:58 +00:00
|
|
|
return false;
|
2016-06-30 00:01:54 +00:00
|
|
|
if (MI0.getNumOperands() != MI1.getNumOperands())
|
2011-01-20 08:34:58 +00:00
|
|
|
return false;
|
|
|
|
|
Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Partial reverts in:
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
X86FixupLEAs.cpp - Some functions return unsigned and arguably should be MCRegister
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
HexagonBitSimplify.cpp - Function takes BitTracker::RegisterRef which appears to be unsigned&
MachineVerifier.cpp - Ambiguous operator==() given MCRegister and const Register
PPCFastISel.cpp - No Register::operator-=()
PeepholeOptimizer.cpp - TargetInstrInfo::optimizeLoadInstr() takes an unsigned&
MachineTraceMetrics.cpp - MachineTraceMetrics lacks a suitable constructor
Manual fixups in:
ARMFastISel.cpp - ARMEmitLoad() now takes a Register& instead of unsigned&
HexagonSplitDouble.cpp - Ternary operator was ambiguous between unsigned/Register
HexagonConstExtenders.cpp - Has a local class named Register, used llvm::Register instead of Register.
PPCFastISel.cpp - PPCEmitLoad() now takes a Register& instead of unsigned&
Depends on D65919
Reviewers: arsenm, bogner, craig.topper, RKSimon
Reviewed By: arsenm
Subscribers: RKSimon, craig.topper, lenary, aemerson, wuzish, jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65962
llvm-svn: 369041
2019-08-15 19:22:08 +00:00
|
|
|
Register Addr0 = MI0.getOperand(1).getReg();
|
|
|
|
Register Addr1 = MI1.getOperand(1).getReg();
|
2011-01-20 08:34:58 +00:00
|
|
|
if (Addr0 != Addr1) {
|
2019-08-01 23:27:28 +00:00
|
|
|
if (!MRI || !Register::isVirtualRegister(Addr0) ||
|
|
|
|
!Register::isVirtualRegister(Addr1))
|
2011-01-20 08:34:58 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// This assumes SSA form.
|
|
|
|
MachineInstr *Def0 = MRI->getVRegDef(Addr0);
|
|
|
|
MachineInstr *Def1 = MRI->getVRegDef(Addr1);
|
|
|
|
// Check if the loaded value, e.g. a constantpool of a global address, are
|
|
|
|
// the same.
|
2016-06-30 00:01:54 +00:00
|
|
|
if (!produceSameValue(*Def0, *Def1, MRI))
|
2011-01-20 08:34:58 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
for (unsigned i = 3, e = MI0.getNumOperands(); i != e; ++i) {
|
2018-01-09 17:31:07 +00:00
|
|
|
// %12 = PICLDR %11, 0, 14, %noreg
|
2016-06-30 00:01:54 +00:00
|
|
|
const MachineOperand &MO0 = MI0.getOperand(i);
|
|
|
|
const MachineOperand &MO1 = MI1.getOperand(i);
|
2011-01-20 08:34:58 +00:00
|
|
|
if (!MO0.isIdenticalTo(MO1))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
2009-11-07 04:04:34 +00:00
|
|
|
}
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
return MI0.isIdenticalTo(MI1, MachineInstr::IgnoreVRegDefs);
|
2009-11-07 04:04:34 +00:00
|
|
|
}
|
|
|
|
|
2010-06-23 23:00:16 +00:00
|
|
|
/// areLoadsFromSameBasePtr - This is used by the pre-regalloc scheduler to
|
|
|
|
/// determine if two loads are loading from the same base address. It should
|
|
|
|
/// only return true if the base pointers are the same and the only differences
|
|
|
|
/// between the two addresses is the offset. It also returns the offsets by
|
|
|
|
/// reference.
|
2012-11-12 19:40:10 +00:00
|
|
|
///
|
|
|
|
/// FIXME: remove this in favor of the MachineInstr interface once pre-RA-sched
|
|
|
|
/// is permanently disabled.
|
2010-06-23 23:00:16 +00:00
|
|
|
bool ARMBaseInstrInfo::areLoadsFromSameBasePtr(SDNode *Load1, SDNode *Load2,
|
|
|
|
int64_t &Offset1,
|
|
|
|
int64_t &Offset2) const {
|
|
|
|
// Don't worry about Thumb: just ARM and Thumb2.
|
|
|
|
if (Subtarget.isThumb1Only()) return false;
|
|
|
|
|
|
|
|
if (!Load1->isMachineOpcode() || !Load2->isMachineOpcode())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
switch (Load1->getMachineOpcode()) {
|
|
|
|
default:
|
|
|
|
return false;
|
2010-10-26 22:37:02 +00:00
|
|
|
case ARM::LDRi12:
|
2010-10-27 00:19:44 +00:00
|
|
|
case ARM::LDRBi12:
|
2010-06-23 23:00:16 +00:00
|
|
|
case ARM::LDRD:
|
|
|
|
case ARM::LDRH:
|
|
|
|
case ARM::LDRSB:
|
|
|
|
case ARM::LDRSH:
|
|
|
|
case ARM::VLDRD:
|
|
|
|
case ARM::VLDRS:
|
|
|
|
case ARM::t2LDRi8:
|
2013-08-14 16:35:29 +00:00
|
|
|
case ARM::t2LDRBi8:
|
2010-06-23 23:00:16 +00:00
|
|
|
case ARM::t2LDRDi8:
|
|
|
|
case ARM::t2LDRSHi8:
|
|
|
|
case ARM::t2LDRi12:
|
2013-08-14 16:35:29 +00:00
|
|
|
case ARM::t2LDRBi12:
|
2010-06-23 23:00:16 +00:00
|
|
|
case ARM::t2LDRSHi12:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (Load2->getMachineOpcode()) {
|
|
|
|
default:
|
|
|
|
return false;
|
2010-10-26 22:37:02 +00:00
|
|
|
case ARM::LDRi12:
|
2010-10-27 00:19:44 +00:00
|
|
|
case ARM::LDRBi12:
|
2010-06-23 23:00:16 +00:00
|
|
|
case ARM::LDRD:
|
|
|
|
case ARM::LDRH:
|
|
|
|
case ARM::LDRSB:
|
|
|
|
case ARM::LDRSH:
|
|
|
|
case ARM::VLDRD:
|
|
|
|
case ARM::VLDRS:
|
|
|
|
case ARM::t2LDRi8:
|
2013-08-14 16:35:29 +00:00
|
|
|
case ARM::t2LDRBi8:
|
2010-06-23 23:00:16 +00:00
|
|
|
case ARM::t2LDRSHi8:
|
|
|
|
case ARM::t2LDRi12:
|
2013-08-14 16:35:29 +00:00
|
|
|
case ARM::t2LDRBi12:
|
2010-06-23 23:00:16 +00:00
|
|
|
case ARM::t2LDRSHi12:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if base addresses and chain operands match.
|
|
|
|
if (Load1->getOperand(0) != Load2->getOperand(0) ||
|
|
|
|
Load1->getOperand(4) != Load2->getOperand(4))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Index should be Reg0.
|
|
|
|
if (Load1->getOperand(3) != Load2->getOperand(3))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Determine the offsets.
|
|
|
|
if (isa<ConstantSDNode>(Load1->getOperand(1)) &&
|
|
|
|
isa<ConstantSDNode>(Load2->getOperand(1))) {
|
|
|
|
Offset1 = cast<ConstantSDNode>(Load1->getOperand(1))->getSExtValue();
|
|
|
|
Offset2 = cast<ConstantSDNode>(Load2->getOperand(1))->getSExtValue();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// shouldScheduleLoadsNear - This is a used by the pre-regalloc scheduler to
|
2011-04-15 05:18:47 +00:00
|
|
|
/// determine (in conjunction with areLoadsFromSameBasePtr) if two loads should
|
2010-06-23 23:00:16 +00:00
|
|
|
/// be scheduled togther. On some targets if two loads are loading from
|
|
|
|
/// addresses in the same cache line, it's better if they are scheduled
|
|
|
|
/// together. This function takes two integers that represent the load offsets
|
|
|
|
/// from the common base address. It returns true if it decides it's desirable
|
|
|
|
/// to schedule the two loads together. "NumLoads" is the number of loads that
|
|
|
|
/// have already been scheduled after Load1.
|
2012-11-12 19:40:10 +00:00
|
|
|
///
|
|
|
|
/// FIXME: remove this in favor of the MachineInstr interface once pre-RA-sched
|
|
|
|
/// is permanently disabled.
|
2010-06-23 23:00:16 +00:00
|
|
|
bool ARMBaseInstrInfo::shouldScheduleLoadsNear(SDNode *Load1, SDNode *Load2,
|
|
|
|
int64_t Offset1, int64_t Offset2,
|
|
|
|
unsigned NumLoads) const {
|
|
|
|
// Don't worry about Thumb: just ARM and Thumb2.
|
|
|
|
if (Subtarget.isThumb1Only()) return false;
|
|
|
|
|
|
|
|
assert(Offset2 > Offset1);
|
|
|
|
|
|
|
|
if ((Offset2 - Offset1) / 8 > 64)
|
|
|
|
return false;
|
|
|
|
|
2013-08-14 16:35:29 +00:00
|
|
|
// Check if the machine opcodes are different. If they are different
|
|
|
|
// then we consider them to not be of the same base address,
|
|
|
|
// EXCEPT in the case of Thumb2 byte loads where one is LDRBi8 and the other LDRBi12.
|
|
|
|
// In this case, they are considered to be the same because they are different
|
|
|
|
// encoding forms of the same basic instruction.
|
|
|
|
if ((Load1->getMachineOpcode() != Load2->getMachineOpcode()) &&
|
|
|
|
!((Load1->getMachineOpcode() == ARM::t2LDRBi8 &&
|
|
|
|
Load2->getMachineOpcode() == ARM::t2LDRBi12) ||
|
|
|
|
(Load1->getMachineOpcode() == ARM::t2LDRBi12 &&
|
|
|
|
Load2->getMachineOpcode() == ARM::t2LDRBi8)))
|
2010-06-23 23:00:16 +00:00
|
|
|
return false; // FIXME: overly conservative?
|
|
|
|
|
|
|
|
// Four loads in a row should be sufficient.
|
|
|
|
if (NumLoads >= 3)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
bool ARMBaseInstrInfo::isSchedulingBoundary(const MachineInstr &MI,
|
2010-06-18 23:09:54 +00:00
|
|
|
const MachineBasicBlock *MBB,
|
|
|
|
const MachineFunction &MF) const {
|
2010-06-25 18:43:14 +00:00
|
|
|
// Debug info is never a scheduling boundary. It's necessary to be explicit
|
|
|
|
// due to the special treatment of IT instructions below, otherwise a
|
|
|
|
// dbg_value followed by an IT will result in the IT instruction being
|
|
|
|
// considered a scheduling hazard, which is wrong. It should be the actual
|
|
|
|
// instruction preceding the dbg_value instruction(s), just like it is
|
|
|
|
// when debug info is not present.
|
2018-05-09 02:42:00 +00:00
|
|
|
if (MI.isDebugInstr())
|
2010-06-25 18:43:14 +00:00
|
|
|
return false;
|
|
|
|
|
2010-06-18 23:09:54 +00:00
|
|
|
// Terminators and labels can't be scheduled around.
|
2016-06-30 00:01:54 +00:00
|
|
|
if (MI.isTerminator() || MI.isPosition())
|
2010-06-18 23:09:54 +00:00
|
|
|
return true;
|
|
|
|
|
|
|
|
// Treat the start of the IT block as a scheduling boundary, but schedule
|
|
|
|
// t2IT along with all instructions following it.
|
|
|
|
// FIXME: This is a big hammer. But the alternative is to add all potential
|
|
|
|
// true and anti dependencies to IT block instructions as implicit operands
|
|
|
|
// to the t2IT instruction. The added compile time and complexity does not
|
|
|
|
// seem worth it.
|
|
|
|
MachineBasicBlock::const_iterator I = MI;
|
2018-05-09 02:42:00 +00:00
|
|
|
// Make sure to skip any debug instructions
|
|
|
|
while (++I != MBB->end() && I->isDebugInstr())
|
2010-06-25 18:43:14 +00:00
|
|
|
;
|
|
|
|
if (I != MBB->end() && I->getOpcode() == ARM::t2IT)
|
2010-06-18 23:09:54 +00:00
|
|
|
return true;
|
|
|
|
|
|
|
|
// Don't attempt to schedule around any instruction that defines
|
|
|
|
// a stack-oriented pointer, as it's unlikely to be profitable. This
|
|
|
|
// saves compile time, because it doesn't require every single
|
|
|
|
// stack slot reference to depend on the instruction that does the
|
|
|
|
// modification.
|
2012-02-21 23:47:43 +00:00
|
|
|
// Calls don't actually change the stack pointer, even if they have imp-defs.
|
2012-02-22 01:07:19 +00:00
|
|
|
// No ARM calling conventions change the stack pointer. (X86 calling
|
|
|
|
// conventions sometimes do).
|
2016-06-30 00:01:54 +00:00
|
|
|
if (!MI.isCall() && MI.definesRegister(ARM::SP))
|
2010-06-18 23:09:54 +00:00
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2011-07-10 02:58:07 +00:00
|
|
|
bool ARMBaseInstrInfo::
|
|
|
|
isProfitableToIfCvt(MachineBasicBlock &MBB,
|
|
|
|
unsigned NumCycles, unsigned ExtraPredCycles,
|
2015-09-10 23:10:42 +00:00
|
|
|
BranchProbability Probability) const {
|
2011-04-13 06:39:16 +00:00
|
|
|
if (!NumCycles)
|
2010-06-25 22:42:03 +00:00
|
|
|
return false;
|
2010-10-05 06:00:33 +00:00
|
|
|
|
2015-04-23 20:31:30 +00:00
|
|
|
// If we are optimizing for size, see if the branch in the predecessor can be
|
|
|
|
// lowered to cbn?z by the constant island lowering pass, and return false if
|
|
|
|
// so. This results in a shorter instruction sequence.
|
2019-04-04 22:40:06 +00:00
|
|
|
if (MBB.getParent()->getFunction().hasOptSize()) {
|
2015-04-23 20:31:30 +00:00
|
|
|
MachineBasicBlock *Pred = *MBB.pred_begin();
|
|
|
|
if (!Pred->empty()) {
|
|
|
|
MachineInstr *LastMI = &*Pred->rbegin();
|
|
|
|
if (LastMI->getOpcode() == ARM::t2Bcc) {
|
2019-04-23 12:11:26 +00:00
|
|
|
const TargetRegisterInfo *TRI = &getRegisterInfo();
|
|
|
|
MachineInstr *CmpMI = findCMPToFoldIntoCBZ(LastMI, TRI);
|
|
|
|
if (CmpMI)
|
|
|
|
return false;
|
2015-04-23 20:31:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-03-14 13:38:45 +00:00
|
|
|
return isProfitableToIfCvt(MBB, NumCycles, ExtraPredCycles,
|
|
|
|
MBB, 0, 0, Probability);
|
2010-06-25 22:42:03 +00:00
|
|
|
}
|
2010-10-05 06:00:33 +00:00
|
|
|
|
2010-06-25 22:42:03 +00:00
|
|
|
bool ARMBaseInstrInfo::
|
2017-06-28 14:11:15 +00:00
|
|
|
isProfitableToIfCvt(MachineBasicBlock &TBB,
|
2010-11-03 00:45:17 +00:00
|
|
|
unsigned TCycles, unsigned TExtra,
|
2017-06-28 14:11:15 +00:00
|
|
|
MachineBasicBlock &FBB,
|
2010-11-03 00:45:17 +00:00
|
|
|
unsigned FCycles, unsigned FExtra,
|
2015-09-10 23:10:42 +00:00
|
|
|
BranchProbability Probability) const {
|
2017-03-14 13:38:45 +00:00
|
|
|
if (!TCycles)
|
2010-09-28 18:32:13 +00:00
|
|
|
return false;
|
2010-10-05 06:00:33 +00:00
|
|
|
|
2019-04-23 11:46:58 +00:00
|
|
|
// In thumb code we often end up trading one branch for a IT block, and
|
|
|
|
// if we are cloning the instruction can increase code size. Prevent
|
|
|
|
// blocks with multiple predecesors from being ifcvted to prevent this
|
|
|
|
// cloning.
|
|
|
|
if (Subtarget.isThumb2() && TBB.getParent()->getFunction().hasMinSize()) {
|
|
|
|
if (TBB.pred_size() != 1 || FBB.pred_size() != 1)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-09-28 18:32:13 +00:00
|
|
|
// Attempt to estimate the relative costs of predication versus branching.
|
2015-09-18 18:19:40 +00:00
|
|
|
// Here we scale up each component of UnpredCost to avoid precision issue when
|
|
|
|
// scaling TCycles/FCycles by Probability.
|
|
|
|
const unsigned ScalingUpFactor = 1024;
|
2017-06-28 14:11:15 +00:00
|
|
|
|
|
|
|
unsigned PredCost = (TCycles + FCycles + TExtra + FExtra) * ScalingUpFactor;
|
|
|
|
unsigned UnpredCost;
|
|
|
|
if (!Subtarget.hasBranchPredictor()) {
|
|
|
|
// When we don't have a branch predictor it's always cheaper to not take a
|
|
|
|
// branch than take it, so we have to take that into account.
|
|
|
|
unsigned NotTakenBranchCost = 1;
|
|
|
|
unsigned TakenBranchCost = Subtarget.getMispredictionPenalty();
|
|
|
|
unsigned TUnpredCycles, FUnpredCycles;
|
|
|
|
if (!FCycles) {
|
|
|
|
// Triangle: TBB is the fallthrough
|
|
|
|
TUnpredCycles = TCycles + NotTakenBranchCost;
|
|
|
|
FUnpredCycles = TakenBranchCost;
|
|
|
|
} else {
|
|
|
|
// Diamond: TBB is the block that is branched to, FBB is the fallthrough
|
|
|
|
TUnpredCycles = TCycles + TakenBranchCost;
|
|
|
|
FUnpredCycles = FCycles + NotTakenBranchCost;
|
2017-07-12 13:23:10 +00:00
|
|
|
// The branch at the end of FBB will disappear when it's predicated, so
|
|
|
|
// discount it from PredCost.
|
|
|
|
PredCost -= 1 * ScalingUpFactor;
|
2017-06-28 14:11:15 +00:00
|
|
|
}
|
|
|
|
// The total cost is the cost of each path scaled by their probabilites
|
|
|
|
unsigned TUnpredCost = Probability.scale(TUnpredCycles * ScalingUpFactor);
|
|
|
|
unsigned FUnpredCost = Probability.getCompl().scale(FUnpredCycles * ScalingUpFactor);
|
|
|
|
UnpredCost = TUnpredCost + FUnpredCost;
|
|
|
|
// When predicating assume that the first IT can be folded away but later
|
|
|
|
// ones cost one cycle each
|
|
|
|
if (Subtarget.isThumb2() && TCycles + FCycles > 4) {
|
|
|
|
PredCost += ((TCycles + FCycles - 4) / 4) * ScalingUpFactor;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
unsigned TUnpredCost = Probability.scale(TCycles * ScalingUpFactor);
|
|
|
|
unsigned FUnpredCost =
|
2015-09-18 18:19:40 +00:00
|
|
|
Probability.getCompl().scale(FCycles * ScalingUpFactor);
|
2017-06-28 14:11:15 +00:00
|
|
|
UnpredCost = TUnpredCost + FUnpredCost;
|
|
|
|
UnpredCost += 1 * ScalingUpFactor; // The branch itself
|
|
|
|
UnpredCost += Subtarget.getMispredictionPenalty() * ScalingUpFactor / 10;
|
|
|
|
}
|
2011-07-10 02:58:07 +00:00
|
|
|
|
2017-06-28 14:11:15 +00:00
|
|
|
return PredCost <= UnpredCost;
|
2010-06-25 22:42:03 +00:00
|
|
|
}
|
|
|
|
|
2019-10-10 09:58:28 +00:00
|
|
|
unsigned
|
|
|
|
ARMBaseInstrInfo::extraSizeToPredicateInstructions(const MachineFunction &MF,
|
|
|
|
unsigned NumInsts) const {
|
|
|
|
// Thumb2 needs a 2-byte IT instruction to predicate up to 4 instructions.
|
|
|
|
// ARM has a condition code field in every predicable instruction, using it
|
|
|
|
// doesn't change code size.
|
|
|
|
return Subtarget.isThumb2() ? divideCeil(NumInsts, 4) * 2 : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned
|
|
|
|
ARMBaseInstrInfo::predictBranchSizeForIfCvt(MachineInstr &MI) const {
|
|
|
|
// If this branch is likely to be folded into the comparison to form a
|
|
|
|
// CB(N)Z, then removing it won't reduce code size at all, because that will
|
|
|
|
// just replace the CB(N)Z with a CMP.
|
|
|
|
if (MI.getOpcode() == ARM::t2Bcc &&
|
|
|
|
findCMPToFoldIntoCBZ(&MI, &getRegisterInfo()))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
unsigned Size = getInstSizeInBytes(MI);
|
|
|
|
|
|
|
|
// For Thumb2, all branches are 32-bit instructions during the if conversion
|
|
|
|
// pass, but may be replaced with 16-bit instructions during size reduction.
|
|
|
|
// Since the branches considered by if conversion tend to be forward branches
|
|
|
|
// over small basic blocks, they are very likely to be in range for the
|
|
|
|
// narrow instructions, so we assume the final code size will be half what it
|
|
|
|
// currently is.
|
|
|
|
if (Subtarget.isThumb2())
|
|
|
|
Size /= 2;
|
|
|
|
|
|
|
|
return Size;
|
|
|
|
}
|
|
|
|
|
2012-09-29 21:43:49 +00:00
|
|
|
bool
|
|
|
|
ARMBaseInstrInfo::isProfitableToUnpredicate(MachineBasicBlock &TMBB,
|
|
|
|
MachineBasicBlock &FMBB) const {
|
2016-06-23 07:47:35 +00:00
|
|
|
// Reduce false anti-dependencies to let the target's out-of-order execution
|
2012-09-29 21:43:49 +00:00
|
|
|
// engine do its thing.
|
2016-06-23 07:47:35 +00:00
|
|
|
return Subtarget.isProfitableToUnpredicate();
|
2012-09-29 21:43:49 +00:00
|
|
|
}
|
|
|
|
|
2009-08-08 03:20:32 +00:00
|
|
|
/// getInstrPredicate - If instruction is predicated, returns its predicate
|
|
|
|
/// condition, otherwise returns AL. It also returns the condition code
|
|
|
|
/// register by reference.
|
2016-02-23 02:46:52 +00:00
|
|
|
ARMCC::CondCodes llvm::getInstrPredicate(const MachineInstr &MI,
|
2020-04-07 17:28:53 -04:00
|
|
|
Register &PredReg) {
|
2016-02-23 02:46:52 +00:00
|
|
|
int PIdx = MI.findFirstPredOperandIdx();
|
2009-08-08 03:20:32 +00:00
|
|
|
if (PIdx == -1) {
|
|
|
|
PredReg = 0;
|
|
|
|
return ARMCC::AL;
|
|
|
|
}
|
|
|
|
|
2016-02-23 02:46:52 +00:00
|
|
|
PredReg = MI.getOperand(PIdx+1).getReg();
|
|
|
|
return (ARMCC::CondCodes)MI.getOperand(PIdx).getImm();
|
2009-08-08 03:20:32 +00:00
|
|
|
}
|
|
|
|
|
2015-05-18 20:27:55 +00:00
|
|
|
unsigned llvm::getMatchingCondBranchOpcode(unsigned Opc) {
|
2009-07-27 18:20:05 +00:00
|
|
|
if (Opc == ARM::B)
|
|
|
|
return ARM::Bcc;
|
2012-01-20 21:51:11 +00:00
|
|
|
if (Opc == ARM::tB)
|
2009-07-27 18:20:05 +00:00
|
|
|
return ARM::tBcc;
|
2012-01-20 21:51:11 +00:00
|
|
|
if (Opc == ARM::t2B)
|
|
|
|
return ARM::t2Bcc;
|
2009-07-27 18:20:05 +00:00
|
|
|
|
|
|
|
llvm_unreachable("Unknown unconditional branch opcode!");
|
|
|
|
}
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
MachineInstr *ARMBaseInstrInfo::commuteInstructionImpl(MachineInstr &MI,
|
2015-09-28 20:33:22 +00:00
|
|
|
bool NewMI,
|
|
|
|
unsigned OpIdx1,
|
|
|
|
unsigned OpIdx2) const {
|
2016-06-30 00:01:54 +00:00
|
|
|
switch (MI.getOpcode()) {
|
2012-04-04 18:23:42 +00:00
|
|
|
case ARM::MOVCCr:
|
|
|
|
case ARM::t2MOVCCr: {
|
|
|
|
// MOVCC can be commuted by inverting the condition.
|
2020-04-07 17:28:53 -04:00
|
|
|
Register PredReg;
|
2016-06-30 00:01:54 +00:00
|
|
|
ARMCC::CondCodes CC = getInstrPredicate(MI, PredReg);
|
2012-04-04 18:23:42 +00:00
|
|
|
// MOVCC AL can't be inverted. Shouldn't happen.
|
|
|
|
if (CC == ARMCC::AL || PredReg != ARM::CPSR)
|
2014-04-25 05:30:21 +00:00
|
|
|
return nullptr;
|
2016-06-30 00:01:54 +00:00
|
|
|
MachineInstr *CommutedMI =
|
|
|
|
TargetInstrInfo::commuteInstructionImpl(MI, NewMI, OpIdx1, OpIdx2);
|
|
|
|
if (!CommutedMI)
|
2014-04-25 05:30:21 +00:00
|
|
|
return nullptr;
|
2012-04-04 18:23:42 +00:00
|
|
|
// After swapping the MOVCC operands, also invert the condition.
|
2016-06-30 00:01:54 +00:00
|
|
|
CommutedMI->getOperand(CommutedMI->findFirstPredOperandIdx())
|
|
|
|
.setImm(ARMCC::getOppositeCondition(CC));
|
|
|
|
return CommutedMI;
|
2012-04-04 18:23:42 +00:00
|
|
|
}
|
|
|
|
}
|
2015-09-28 20:33:22 +00:00
|
|
|
return TargetInstrInfo::commuteInstructionImpl(MI, NewMI, OpIdx1, OpIdx2);
|
2012-04-04 18:23:42 +00:00
|
|
|
}
|
2009-07-28 05:48:47 +00:00
|
|
|
|
2012-08-15 22:16:39 +00:00
|
|
|
/// Identify instructions that can be folded into a MOVCC instruction, and
|
Use predication instead of pseudo-opcodes when folding into MOVCC.
Now that it is possible to dynamically tie MachineInstr operands,
predicated instructions are possible in SSA form:
%vreg3<def> = SUBri %vreg1, -2147483647, pred:14, pred:%noreg, %opt:%noreg
%vreg4<def,tied1> = MOVCCr %vreg3<tied0>, %vreg1, %pred:12, pred:%CPSR
Becomes a predicated SUBri with a tied imp-use:
SUBri %vreg1, -2147483647, pred:13, pred:%CPSR, opt:%noreg, %vreg1<imp-use,tied0>
This means that any instruction that is safe to move can be folded into
a MOVCC, and the *CC pseudo-instructions are no longer needed.
The test case changes reflect that Thumb2SizeReduce recognizes the
predicated instructions. It didn't understand the pseudos.
llvm-svn: 163274
2012-09-05 23:58:02 +00:00
|
|
|
/// return the defining instruction.
|
[ARM] Comply with rules on ARMv8-A thumb mode partial deprecation of IT.
Summary:
When identifing instructions that can be folded into a MOVCC instruction,
checking for a predicate operand is not enough, also need to check for
thumb2 function, with restrict-IT, is the machine instruction eligible for
ARMv8 IT or not.
Notes in ARMv8-A Architecture Reference Manual, section "Partial deprecation of IT"
https://usermanual.wiki/Pdf/ARM20Architecture20Reference20ManualARMv8.1667877052.pdf
"ARMv8-A deprecates some uses of the T32 IT instruction. All uses of IT that apply to
instructions other than a single subsequent 16-bit instruction from a restricted set
are deprecated, as are explicit references to the PC within that single 16-bit
instruction. This permits the non-deprecated forms of IT and subsequent instructions
to be treated as a single 32-bit conditional instruction."
Reviewers: efriedma, lebedev.ri, t.p.northover, jmolloy, aemerson, compnerd, stoklund, ostannard
Reviewed By: ostannard
Subscribers: ostannard, javed.absar, kristof.beyls, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63474
llvm-svn: 363739
2019-06-18 20:55:09 +00:00
|
|
|
MachineInstr *
|
2020-04-07 17:28:53 -04:00
|
|
|
ARMBaseInstrInfo::canFoldIntoMOVCC(Register Reg, const MachineRegisterInfo &MRI,
|
[ARM] Comply with rules on ARMv8-A thumb mode partial deprecation of IT.
Summary:
When identifing instructions that can be folded into a MOVCC instruction,
checking for a predicate operand is not enough, also need to check for
thumb2 function, with restrict-IT, is the machine instruction eligible for
ARMv8 IT or not.
Notes in ARMv8-A Architecture Reference Manual, section "Partial deprecation of IT"
https://usermanual.wiki/Pdf/ARM20Architecture20Reference20ManualARMv8.1667877052.pdf
"ARMv8-A deprecates some uses of the T32 IT instruction. All uses of IT that apply to
instructions other than a single subsequent 16-bit instruction from a restricted set
are deprecated, as are explicit references to the PC within that single 16-bit
instruction. This permits the non-deprecated forms of IT and subsequent instructions
to be treated as a single 32-bit conditional instruction."
Reviewers: efriedma, lebedev.ri, t.p.northover, jmolloy, aemerson, compnerd, stoklund, ostannard
Reviewed By: ostannard
Subscribers: ostannard, javed.absar, kristof.beyls, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63474
llvm-svn: 363739
2019-06-18 20:55:09 +00:00
|
|
|
const TargetInstrInfo *TII) const {
|
2020-04-07 17:28:53 -04:00
|
|
|
if (!Reg.isVirtual())
|
2014-04-25 05:30:21 +00:00
|
|
|
return nullptr;
|
2012-08-15 22:16:39 +00:00
|
|
|
if (!MRI.hasOneNonDBGUse(Reg))
|
2014-04-25 05:30:21 +00:00
|
|
|
return nullptr;
|
Use predication instead of pseudo-opcodes when folding into MOVCC.
Now that it is possible to dynamically tie MachineInstr operands,
predicated instructions are possible in SSA form:
%vreg3<def> = SUBri %vreg1, -2147483647, pred:14, pred:%noreg, %opt:%noreg
%vreg4<def,tied1> = MOVCCr %vreg3<tied0>, %vreg1, %pred:12, pred:%CPSR
Becomes a predicated SUBri with a tied imp-use:
SUBri %vreg1, -2147483647, pred:13, pred:%CPSR, opt:%noreg, %vreg1<imp-use,tied0>
This means that any instruction that is safe to move can be folded into
a MOVCC, and the *CC pseudo-instructions are no longer needed.
The test case changes reflect that Thumb2SizeReduce recognizes the
predicated instructions. It didn't understand the pseudos.
llvm-svn: 163274
2012-09-05 23:58:02 +00:00
|
|
|
MachineInstr *MI = MRI.getVRegDef(Reg);
|
2012-08-15 22:16:39 +00:00
|
|
|
if (!MI)
|
2014-04-25 05:30:21 +00:00
|
|
|
return nullptr;
|
[ARM] Comply with rules on ARMv8-A thumb mode partial deprecation of IT.
Summary:
When identifing instructions that can be folded into a MOVCC instruction,
checking for a predicate operand is not enough, also need to check for
thumb2 function, with restrict-IT, is the machine instruction eligible for
ARMv8 IT or not.
Notes in ARMv8-A Architecture Reference Manual, section "Partial deprecation of IT"
https://usermanual.wiki/Pdf/ARM20Architecture20Reference20ManualARMv8.1667877052.pdf
"ARMv8-A deprecates some uses of the T32 IT instruction. All uses of IT that apply to
instructions other than a single subsequent 16-bit instruction from a restricted set
are deprecated, as are explicit references to the PC within that single 16-bit
instruction. This permits the non-deprecated forms of IT and subsequent instructions
to be treated as a single 32-bit conditional instruction."
Reviewers: efriedma, lebedev.ri, t.p.northover, jmolloy, aemerson, compnerd, stoklund, ostannard
Reviewed By: ostannard
Subscribers: ostannard, javed.absar, kristof.beyls, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63474
llvm-svn: 363739
2019-06-18 20:55:09 +00:00
|
|
|
// Check if MI can be predicated and folded into the MOVCC.
|
|
|
|
if (!isPredicable(*MI))
|
2014-04-25 05:30:21 +00:00
|
|
|
return nullptr;
|
2012-08-15 22:16:39 +00:00
|
|
|
// Check if MI has any non-dead defs or physreg uses. This also detects
|
|
|
|
// predicated instructions which will be reading CPSR.
|
|
|
|
for (unsigned i = 1, e = MI->getNumOperands(); i != e; ++i) {
|
|
|
|
const MachineOperand &MO = MI->getOperand(i);
|
2012-08-17 20:55:34 +00:00
|
|
|
// Reject frame index operands, PEI can't handle the predicated pseudos.
|
|
|
|
if (MO.isFI() || MO.isCPI() || MO.isJTI())
|
2014-04-25 05:30:21 +00:00
|
|
|
return nullptr;
|
2012-08-15 22:16:39 +00:00
|
|
|
if (!MO.isReg())
|
|
|
|
continue;
|
Use predication instead of pseudo-opcodes when folding into MOVCC.
Now that it is possible to dynamically tie MachineInstr operands,
predicated instructions are possible in SSA form:
%vreg3<def> = SUBri %vreg1, -2147483647, pred:14, pred:%noreg, %opt:%noreg
%vreg4<def,tied1> = MOVCCr %vreg3<tied0>, %vreg1, %pred:12, pred:%CPSR
Becomes a predicated SUBri with a tied imp-use:
SUBri %vreg1, -2147483647, pred:13, pred:%CPSR, opt:%noreg, %vreg1<imp-use,tied0>
This means that any instruction that is safe to move can be folded into
a MOVCC, and the *CC pseudo-instructions are no longer needed.
The test case changes reflect that Thumb2SizeReduce recognizes the
predicated instructions. It didn't understand the pseudos.
llvm-svn: 163274
2012-09-05 23:58:02 +00:00
|
|
|
// MI can't have any tied operands, that would conflict with predication.
|
|
|
|
if (MO.isTied())
|
2014-04-25 05:30:21 +00:00
|
|
|
return nullptr;
|
2019-08-01 23:27:28 +00:00
|
|
|
if (Register::isPhysicalRegister(MO.getReg()))
|
2014-04-25 05:30:21 +00:00
|
|
|
return nullptr;
|
2012-08-15 22:16:39 +00:00
|
|
|
if (MO.isDef() && !MO.isDead())
|
2014-04-25 05:30:21 +00:00
|
|
|
return nullptr;
|
2012-08-15 22:16:39 +00:00
|
|
|
}
|
Use predication instead of pseudo-opcodes when folding into MOVCC.
Now that it is possible to dynamically tie MachineInstr operands,
predicated instructions are possible in SSA form:
%vreg3<def> = SUBri %vreg1, -2147483647, pred:14, pred:%noreg, %opt:%noreg
%vreg4<def,tied1> = MOVCCr %vreg3<tied0>, %vreg1, %pred:12, pred:%CPSR
Becomes a predicated SUBri with a tied imp-use:
SUBri %vreg1, -2147483647, pred:13, pred:%CPSR, opt:%noreg, %vreg1<imp-use,tied0>
This means that any instruction that is safe to move can be folded into
a MOVCC, and the *CC pseudo-instructions are no longer needed.
The test case changes reflect that Thumb2SizeReduce recognizes the
predicated instructions. It didn't understand the pseudos.
llvm-svn: 163274
2012-09-05 23:58:02 +00:00
|
|
|
bool DontMoveAcrossStores = true;
|
2015-05-19 21:22:20 +00:00
|
|
|
if (!MI->isSafeToMove(/* AliasAnalysis = */ nullptr, DontMoveAcrossStores))
|
2014-04-25 05:30:21 +00:00
|
|
|
return nullptr;
|
Use predication instead of pseudo-opcodes when folding into MOVCC.
Now that it is possible to dynamically tie MachineInstr operands,
predicated instructions are possible in SSA form:
%vreg3<def> = SUBri %vreg1, -2147483647, pred:14, pred:%noreg, %opt:%noreg
%vreg4<def,tied1> = MOVCCr %vreg3<tied0>, %vreg1, %pred:12, pred:%CPSR
Becomes a predicated SUBri with a tied imp-use:
SUBri %vreg1, -2147483647, pred:13, pred:%CPSR, opt:%noreg, %vreg1<imp-use,tied0>
This means that any instruction that is safe to move can be folded into
a MOVCC, and the *CC pseudo-instructions are no longer needed.
The test case changes reflect that Thumb2SizeReduce recognizes the
predicated instructions. It didn't understand the pseudos.
llvm-svn: 163274
2012-09-05 23:58:02 +00:00
|
|
|
return MI;
|
2012-08-15 22:16:39 +00:00
|
|
|
}
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
bool ARMBaseInstrInfo::analyzeSelect(const MachineInstr &MI,
|
2012-08-16 23:14:20 +00:00
|
|
|
SmallVectorImpl<MachineOperand> &Cond,
|
|
|
|
unsigned &TrueOp, unsigned &FalseOp,
|
|
|
|
bool &Optimizable) const {
|
2016-06-30 00:01:54 +00:00
|
|
|
assert((MI.getOpcode() == ARM::MOVCCr || MI.getOpcode() == ARM::t2MOVCCr) &&
|
2012-08-16 23:14:20 +00:00
|
|
|
"Unknown select instruction");
|
|
|
|
// MOVCC operands:
|
|
|
|
// 0: Def.
|
|
|
|
// 1: True use.
|
|
|
|
// 2: False use.
|
|
|
|
// 3: Condition code.
|
|
|
|
// 4: CPSR use.
|
|
|
|
TrueOp = 1;
|
|
|
|
FalseOp = 2;
|
2016-06-30 00:01:54 +00:00
|
|
|
Cond.push_back(MI.getOperand(3));
|
|
|
|
Cond.push_back(MI.getOperand(4));
|
2012-08-16 23:14:20 +00:00
|
|
|
// We can always fold a def.
|
|
|
|
Optimizable = true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-01-13 07:07:13 +00:00
|
|
|
MachineInstr *
|
2016-06-30 00:01:54 +00:00
|
|
|
ARMBaseInstrInfo::optimizeSelect(MachineInstr &MI,
|
2015-01-13 07:07:13 +00:00
|
|
|
SmallPtrSetImpl<MachineInstr *> &SeenMIs,
|
|
|
|
bool PreferFalse) const {
|
2016-06-30 00:01:54 +00:00
|
|
|
assert((MI.getOpcode() == ARM::MOVCCr || MI.getOpcode() == ARM::t2MOVCCr) &&
|
2012-08-16 23:14:20 +00:00
|
|
|
"Unknown select instruction");
|
2016-06-30 00:01:54 +00:00
|
|
|
MachineRegisterInfo &MRI = MI.getParent()->getParent()->getRegInfo();
|
|
|
|
MachineInstr *DefMI = canFoldIntoMOVCC(MI.getOperand(2).getReg(), MRI, this);
|
Use predication instead of pseudo-opcodes when folding into MOVCC.
Now that it is possible to dynamically tie MachineInstr operands,
predicated instructions are possible in SSA form:
%vreg3<def> = SUBri %vreg1, -2147483647, pred:14, pred:%noreg, %opt:%noreg
%vreg4<def,tied1> = MOVCCr %vreg3<tied0>, %vreg1, %pred:12, pred:%CPSR
Becomes a predicated SUBri with a tied imp-use:
SUBri %vreg1, -2147483647, pred:13, pred:%CPSR, opt:%noreg, %vreg1<imp-use,tied0>
This means that any instruction that is safe to move can be folded into
a MOVCC, and the *CC pseudo-instructions are no longer needed.
The test case changes reflect that Thumb2SizeReduce recognizes the
predicated instructions. It didn't understand the pseudos.
llvm-svn: 163274
2012-09-05 23:58:02 +00:00
|
|
|
bool Invert = !DefMI;
|
|
|
|
if (!DefMI)
|
2016-06-30 00:01:54 +00:00
|
|
|
DefMI = canFoldIntoMOVCC(MI.getOperand(1).getReg(), MRI, this);
|
Use predication instead of pseudo-opcodes when folding into MOVCC.
Now that it is possible to dynamically tie MachineInstr operands,
predicated instructions are possible in SSA form:
%vreg3<def> = SUBri %vreg1, -2147483647, pred:14, pred:%noreg, %opt:%noreg
%vreg4<def,tied1> = MOVCCr %vreg3<tied0>, %vreg1, %pred:12, pred:%CPSR
Becomes a predicated SUBri with a tied imp-use:
SUBri %vreg1, -2147483647, pred:13, pred:%CPSR, opt:%noreg, %vreg1<imp-use,tied0>
This means that any instruction that is safe to move can be folded into
a MOVCC, and the *CC pseudo-instructions are no longer needed.
The test case changes reflect that Thumb2SizeReduce recognizes the
predicated instructions. It didn't understand the pseudos.
llvm-svn: 163274
2012-09-05 23:58:02 +00:00
|
|
|
if (!DefMI)
|
2014-04-25 05:30:21 +00:00
|
|
|
return nullptr;
|
2012-08-16 23:14:20 +00:00
|
|
|
|
2013-10-04 16:52:56 +00:00
|
|
|
// Find new register class to use.
|
2016-06-30 00:01:54 +00:00
|
|
|
MachineOperand FalseReg = MI.getOperand(Invert ? 2 : 1);
|
Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Partial reverts in:
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
X86FixupLEAs.cpp - Some functions return unsigned and arguably should be MCRegister
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
HexagonBitSimplify.cpp - Function takes BitTracker::RegisterRef which appears to be unsigned&
MachineVerifier.cpp - Ambiguous operator==() given MCRegister and const Register
PPCFastISel.cpp - No Register::operator-=()
PeepholeOptimizer.cpp - TargetInstrInfo::optimizeLoadInstr() takes an unsigned&
MachineTraceMetrics.cpp - MachineTraceMetrics lacks a suitable constructor
Manual fixups in:
ARMFastISel.cpp - ARMEmitLoad() now takes a Register& instead of unsigned&
HexagonSplitDouble.cpp - Ternary operator was ambiguous between unsigned/Register
HexagonConstExtenders.cpp - Has a local class named Register, used llvm::Register instead of Register.
PPCFastISel.cpp - PPCEmitLoad() now takes a Register& instead of unsigned&
Depends on D65919
Reviewers: arsenm, bogner, craig.topper, RKSimon
Reviewed By: arsenm
Subscribers: RKSimon, craig.topper, lenary, aemerson, wuzish, jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65962
llvm-svn: 369041
2019-08-15 19:22:08 +00:00
|
|
|
Register DestReg = MI.getOperand(0).getReg();
|
2013-10-04 16:52:56 +00:00
|
|
|
const TargetRegisterClass *PreviousClass = MRI.getRegClass(FalseReg.getReg());
|
|
|
|
if (!MRI.constrainRegClass(DestReg, PreviousClass))
|
2014-04-25 05:30:21 +00:00
|
|
|
return nullptr;
|
2013-10-04 16:52:56 +00:00
|
|
|
|
2012-08-16 23:14:20 +00:00
|
|
|
// Create a new predicated version of DefMI.
|
|
|
|
// Rfalse is the first use.
|
2016-06-30 00:01:54 +00:00
|
|
|
MachineInstrBuilder NewMI =
|
|
|
|
BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), DefMI->getDesc(), DestReg);
|
2012-08-16 23:14:20 +00:00
|
|
|
|
|
|
|
// Copy all the DefMI operands, excluding its (null) predicate.
|
|
|
|
const MCInstrDesc &DefDesc = DefMI->getDesc();
|
|
|
|
for (unsigned i = 1, e = DefDesc.getNumOperands();
|
|
|
|
i != e && !DefDesc.OpInfo[i].isPredicate(); ++i)
|
2017-01-13 09:58:52 +00:00
|
|
|
NewMI.add(DefMI->getOperand(i));
|
2012-08-16 23:14:20 +00:00
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
unsigned CondCode = MI.getOperand(3).getImm();
|
2012-08-16 23:14:20 +00:00
|
|
|
if (Invert)
|
|
|
|
NewMI.addImm(ARMCC::getOppositeCondition(ARMCC::CondCodes(CondCode)));
|
|
|
|
else
|
|
|
|
NewMI.addImm(CondCode);
|
2017-01-13 09:58:52 +00:00
|
|
|
NewMI.add(MI.getOperand(4));
|
2012-08-16 23:14:20 +00:00
|
|
|
|
|
|
|
// DefMI is not the -S version that sets CPSR, so add an optional %noreg.
|
|
|
|
if (NewMI->hasOptionalDef())
|
2017-01-13 10:18:01 +00:00
|
|
|
NewMI.add(condCodeOp());
|
2012-08-16 23:14:20 +00:00
|
|
|
|
Use predication instead of pseudo-opcodes when folding into MOVCC.
Now that it is possible to dynamically tie MachineInstr operands,
predicated instructions are possible in SSA form:
%vreg3<def> = SUBri %vreg1, -2147483647, pred:14, pred:%noreg, %opt:%noreg
%vreg4<def,tied1> = MOVCCr %vreg3<tied0>, %vreg1, %pred:12, pred:%CPSR
Becomes a predicated SUBri with a tied imp-use:
SUBri %vreg1, -2147483647, pred:13, pred:%CPSR, opt:%noreg, %vreg1<imp-use,tied0>
This means that any instruction that is safe to move can be folded into
a MOVCC, and the *CC pseudo-instructions are no longer needed.
The test case changes reflect that Thumb2SizeReduce recognizes the
predicated instructions. It didn't understand the pseudos.
llvm-svn: 163274
2012-09-05 23:58:02 +00:00
|
|
|
// The output register value when the predicate is false is an implicit
|
|
|
|
// register operand tied to the first def.
|
|
|
|
// The tie makes the register allocator ensure the FalseReg is allocated the
|
|
|
|
// same register as operand 0.
|
|
|
|
FalseReg.setImplicit();
|
2017-01-13 09:58:52 +00:00
|
|
|
NewMI.add(FalseReg);
|
Use predication instead of pseudo-opcodes when folding into MOVCC.
Now that it is possible to dynamically tie MachineInstr operands,
predicated instructions are possible in SSA form:
%vreg3<def> = SUBri %vreg1, -2147483647, pred:14, pred:%noreg, %opt:%noreg
%vreg4<def,tied1> = MOVCCr %vreg3<tied0>, %vreg1, %pred:12, pred:%CPSR
Becomes a predicated SUBri with a tied imp-use:
SUBri %vreg1, -2147483647, pred:13, pred:%CPSR, opt:%noreg, %vreg1<imp-use,tied0>
This means that any instruction that is safe to move can be folded into
a MOVCC, and the *CC pseudo-instructions are no longer needed.
The test case changes reflect that Thumb2SizeReduce recognizes the
predicated instructions. It didn't understand the pseudos.
llvm-svn: 163274
2012-09-05 23:58:02 +00:00
|
|
|
NewMI->tieOperands(0, NewMI->getNumOperands() - 1);
|
|
|
|
|
2015-01-13 07:07:13 +00:00
|
|
|
// Update SeenMIs set: register newly created MI and erase removed DefMI.
|
|
|
|
SeenMIs.insert(NewMI);
|
|
|
|
SeenMIs.erase(DefMI);
|
|
|
|
|
2015-04-30 23:57:47 +00:00
|
|
|
// If MI is inside a loop, and DefMI is outside the loop, then kill flags on
|
|
|
|
// DefMI would be invalid when tranferred inside the loop. Checking for a
|
|
|
|
// loop is expensive, but at least remove kill flags if they are in different
|
|
|
|
// BBs.
|
2016-06-30 00:01:54 +00:00
|
|
|
if (DefMI->getParent() != MI.getParent())
|
2015-04-30 23:57:47 +00:00
|
|
|
NewMI->clearKillInfo();
|
|
|
|
|
2012-08-16 23:14:20 +00:00
|
|
|
// The caller will erase MI, but not DefMI.
|
|
|
|
DefMI->eraseFromParent();
|
|
|
|
return NewMI;
|
|
|
|
}
|
|
|
|
|
2011-09-21 02:20:46 +00:00
|
|
|
/// Map pseudo instructions that imply an 'S' bit onto real opcodes. Whether the
|
|
|
|
/// instruction is encoded with an 'S' bit is determined by the optional CPSR
|
|
|
|
/// def operand.
|
|
|
|
///
|
|
|
|
/// This will go away once we can teach tblgen how to set the optional CPSR def
|
|
|
|
/// operand itself.
|
|
|
|
struct AddSubFlagsOpcodePair {
|
2012-05-24 03:59:11 +00:00
|
|
|
uint16_t PseudoOpc;
|
|
|
|
uint16_t MachineOpc;
|
2011-09-21 02:20:46 +00:00
|
|
|
};
|
|
|
|
|
2012-05-24 03:59:11 +00:00
|
|
|
static const AddSubFlagsOpcodePair AddSubFlagsOpcodeMap[] = {
|
2011-09-21 02:20:46 +00:00
|
|
|
{ARM::ADDSri, ARM::ADDri},
|
|
|
|
{ARM::ADDSrr, ARM::ADDrr},
|
|
|
|
{ARM::ADDSrsi, ARM::ADDrsi},
|
|
|
|
{ARM::ADDSrsr, ARM::ADDrsr},
|
|
|
|
|
|
|
|
{ARM::SUBSri, ARM::SUBri},
|
|
|
|
{ARM::SUBSrr, ARM::SUBrr},
|
|
|
|
{ARM::SUBSrsi, ARM::SUBrsi},
|
|
|
|
{ARM::SUBSrsr, ARM::SUBrsr},
|
|
|
|
|
|
|
|
{ARM::RSBSri, ARM::RSBri},
|
|
|
|
{ARM::RSBSrsi, ARM::RSBrsi},
|
|
|
|
{ARM::RSBSrsr, ARM::RSBrsr},
|
|
|
|
|
2017-03-22 23:35:51 +00:00
|
|
|
{ARM::tADDSi3, ARM::tADDi3},
|
|
|
|
{ARM::tADDSi8, ARM::tADDi8},
|
|
|
|
{ARM::tADDSrr, ARM::tADDrr},
|
|
|
|
{ARM::tADCS, ARM::tADC},
|
|
|
|
|
|
|
|
{ARM::tSUBSi3, ARM::tSUBi3},
|
|
|
|
{ARM::tSUBSi8, ARM::tSUBi8},
|
|
|
|
{ARM::tSUBSrr, ARM::tSUBrr},
|
|
|
|
{ARM::tSBCS, ARM::tSBC},
|
2018-10-31 21:45:48 +00:00
|
|
|
{ARM::tRSBS, ARM::tRSB},
|
2019-07-31 23:19:21 +00:00
|
|
|
{ARM::tLSLSri, ARM::tLSLri},
|
2017-03-22 23:35:51 +00:00
|
|
|
|
2011-09-21 02:20:46 +00:00
|
|
|
{ARM::t2ADDSri, ARM::t2ADDri},
|
|
|
|
{ARM::t2ADDSrr, ARM::t2ADDrr},
|
|
|
|
{ARM::t2ADDSrs, ARM::t2ADDrs},
|
|
|
|
|
|
|
|
{ARM::t2SUBSri, ARM::t2SUBri},
|
|
|
|
{ARM::t2SUBSrr, ARM::t2SUBrr},
|
|
|
|
{ARM::t2SUBSrs, ARM::t2SUBrs},
|
|
|
|
|
|
|
|
{ARM::t2RSBSri, ARM::t2RSBri},
|
|
|
|
{ARM::t2RSBSrs, ARM::t2RSBrs},
|
|
|
|
};
|
|
|
|
|
|
|
|
unsigned llvm::convertAddSubFlagsOpcode(unsigned OldOpc) {
|
2012-05-24 03:59:11 +00:00
|
|
|
for (unsigned i = 0, e = array_lengthof(AddSubFlagsOpcodeMap); i != e; ++i)
|
|
|
|
if (OldOpc == AddSubFlagsOpcodeMap[i].PseudoOpc)
|
|
|
|
return AddSubFlagsOpcodeMap[i].MachineOpc;
|
2011-09-21 02:20:46 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-07-28 05:48:47 +00:00
|
|
|
void llvm::emitARMRegPlusImmediate(MachineBasicBlock &MBB,
|
2016-06-12 15:39:02 +00:00
|
|
|
MachineBasicBlock::iterator &MBBI,
|
2020-04-07 17:28:53 -04:00
|
|
|
const DebugLoc &dl, Register DestReg,
|
|
|
|
Register BaseReg, int NumBytes,
|
|
|
|
ARMCC::CondCodes Pred, Register PredReg,
|
2016-06-12 15:39:02 +00:00
|
|
|
const ARMBaseInstrInfo &TII,
|
|
|
|
unsigned MIFlags) {
|
2013-11-04 23:04:15 +00:00
|
|
|
if (NumBytes == 0 && DestReg != BaseReg) {
|
|
|
|
BuildMI(MBB, MBBI, dl, TII.get(ARM::MOVr), DestReg)
|
2017-01-20 08:15:24 +00:00
|
|
|
.addReg(BaseReg, RegState::Kill)
|
|
|
|
.add(predOps(Pred, PredReg))
|
|
|
|
.add(condCodeOp())
|
|
|
|
.setMIFlags(MIFlags);
|
2013-11-04 23:04:15 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-07-28 05:48:47 +00:00
|
|
|
bool isSub = NumBytes < 0;
|
|
|
|
if (isSub) NumBytes = -NumBytes;
|
|
|
|
|
|
|
|
while (NumBytes) {
|
|
|
|
unsigned RotAmt = ARM_AM::getSOImmValRotate(NumBytes);
|
|
|
|
unsigned ThisVal = NumBytes & ARM_AM::rotr32(0xFF, RotAmt);
|
|
|
|
assert(ThisVal && "Didn't extract field correctly");
|
|
|
|
|
|
|
|
// We will handle these bits from offset, clear them.
|
|
|
|
NumBytes &= ~ThisVal;
|
|
|
|
|
|
|
|
assert(ARM_AM::getSOImmVal(ThisVal) != -1 && "Bit extraction didn't work?");
|
|
|
|
|
|
|
|
// Build the new ADD / SUB.
|
|
|
|
unsigned Opc = isSub ? ARM::SUBri : ARM::ADDri;
|
|
|
|
BuildMI(MBB, MBBI, dl, TII.get(Opc), DestReg)
|
2017-01-20 08:15:24 +00:00
|
|
|
.addReg(BaseReg, RegState::Kill)
|
|
|
|
.addImm(ThisVal)
|
|
|
|
.add(predOps(Pred, PredReg))
|
|
|
|
.add(condCodeOp())
|
|
|
|
.setMIFlags(MIFlags);
|
2009-07-28 05:48:47 +00:00
|
|
|
BaseReg = DestReg;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-02 14:46:26 +00:00
|
|
|
bool llvm::tryFoldSPUpdateIntoPushPop(const ARMSubtarget &Subtarget,
|
|
|
|
MachineFunction &MF, MachineInstr *MI,
|
2013-11-08 17:18:07 +00:00
|
|
|
unsigned NumBytes) {
|
|
|
|
// This optimisation potentially adds lots of load and store
|
|
|
|
// micro-operations, it's only really a great benefit to code-size.
|
2019-04-04 22:40:06 +00:00
|
|
|
if (!Subtarget.hasMinSize())
|
2013-11-08 17:18:07 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// If only one register is pushed/popped, LLVM can use an LDR/STR
|
|
|
|
// instead. We can't modify those so make sure we're dealing with an
|
|
|
|
// instruction we understand.
|
|
|
|
bool IsPop = isPopOpcode(MI->getOpcode());
|
|
|
|
bool IsPush = isPushOpcode(MI->getOpcode());
|
|
|
|
if (!IsPush && !IsPop)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
bool IsVFPPushPop = MI->getOpcode() == ARM::VSTMDDB_UPD ||
|
|
|
|
MI->getOpcode() == ARM::VLDMDIA_UPD;
|
|
|
|
bool IsT1PushPop = MI->getOpcode() == ARM::tPUSH ||
|
|
|
|
MI->getOpcode() == ARM::tPOP ||
|
|
|
|
MI->getOpcode() == ARM::tPOP_RET;
|
|
|
|
|
|
|
|
assert((IsT1PushPop || (MI->getOperand(0).getReg() == ARM::SP &&
|
|
|
|
MI->getOperand(1).getReg() == ARM::SP)) &&
|
|
|
|
"trying to fold sp update into non-sp-updating push/pop");
|
|
|
|
|
|
|
|
// The VFP push & pop act on D-registers, so we can only fold an adjustment
|
|
|
|
// by a multiple of 8 bytes in correctly. Similarly rN is 4-bytes. Don't try
|
|
|
|
// if this is violated.
|
|
|
|
if (NumBytes % (IsVFPPushPop ? 8 : 4) != 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// ARM and Thumb2 push/pop insts have explicit "sp, sp" operands (+
|
|
|
|
// pred) so the list starts at 4. Thumb1 starts after the predicate.
|
|
|
|
int RegListIdx = IsT1PushPop ? 2 : 4;
|
|
|
|
|
|
|
|
// Calculate the space we'll need in terms of registers.
|
ARM: don't rely on push/pop reglists being in order when folding SP adjust.
It would be a very nice invariant to rely on, but unfortunately it doesn't
necessarily hold (and the causes of mis-sorted reglists appear to be quite
varied) so to be robust the frame lowering code can't assume that the first
register in the list is also the first one that actually gets pushed.
Should fix an issue where we were turning something like:
push {r8, r4, r7, lr}
sub sp, #24
into nonsense like:
push {r2, r3, r4, r5, r6, r7, r8, r4, r7, lr}
llvm-svn: 285232
2016-10-26 20:01:00 +00:00
|
|
|
unsigned RegsNeeded;
|
|
|
|
const TargetRegisterClass *RegClass;
|
2013-11-08 17:18:07 +00:00
|
|
|
if (IsVFPPushPop) {
|
|
|
|
RegsNeeded = NumBytes / 8;
|
ARM: don't rely on push/pop reglists being in order when folding SP adjust.
It would be a very nice invariant to rely on, but unfortunately it doesn't
necessarily hold (and the causes of mis-sorted reglists appear to be quite
varied) so to be robust the frame lowering code can't assume that the first
register in the list is also the first one that actually gets pushed.
Should fix an issue where we were turning something like:
push {r8, r4, r7, lr}
sub sp, #24
into nonsense like:
push {r2, r3, r4, r5, r6, r7, r8, r4, r7, lr}
llvm-svn: 285232
2016-10-26 20:01:00 +00:00
|
|
|
RegClass = &ARM::DPRRegClass;
|
2013-11-08 17:18:07 +00:00
|
|
|
} else {
|
|
|
|
RegsNeeded = NumBytes / 4;
|
ARM: don't rely on push/pop reglists being in order when folding SP adjust.
It would be a very nice invariant to rely on, but unfortunately it doesn't
necessarily hold (and the causes of mis-sorted reglists appear to be quite
varied) so to be robust the frame lowering code can't assume that the first
register in the list is also the first one that actually gets pushed.
Should fix an issue where we were turning something like:
push {r8, r4, r7, lr}
sub sp, #24
into nonsense like:
push {r2, r3, r4, r5, r6, r7, r8, r4, r7, lr}
llvm-svn: 285232
2016-10-26 20:01:00 +00:00
|
|
|
RegClass = &ARM::GPRRegClass;
|
2013-11-08 17:18:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// We're going to have to strip all list operands off before
|
|
|
|
// re-adding them since the order matters, so save the existing ones
|
|
|
|
// for later.
|
|
|
|
SmallVector<MachineOperand, 4> RegList;
|
ARM: don't rely on push/pop reglists being in order when folding SP adjust.
It would be a very nice invariant to rely on, but unfortunately it doesn't
necessarily hold (and the causes of mis-sorted reglists appear to be quite
varied) so to be robust the frame lowering code can't assume that the first
register in the list is also the first one that actually gets pushed.
Should fix an issue where we were turning something like:
push {r8, r4, r7, lr}
sub sp, #24
into nonsense like:
push {r2, r3, r4, r5, r6, r7, r8, r4, r7, lr}
llvm-svn: 285232
2016-10-26 20:01:00 +00:00
|
|
|
|
|
|
|
// We're also going to need the first register transferred by this
|
|
|
|
// instruction, which won't necessarily be the first register in the list.
|
|
|
|
unsigned FirstRegEnc = -1;
|
2013-11-08 17:18:07 +00:00
|
|
|
|
|
|
|
const TargetRegisterInfo *TRI = MF.getRegInfo().getTargetRegisterInfo();
|
ARM: don't rely on push/pop reglists being in order when folding SP adjust.
It would be a very nice invariant to rely on, but unfortunately it doesn't
necessarily hold (and the causes of mis-sorted reglists appear to be quite
varied) so to be robust the frame lowering code can't assume that the first
register in the list is also the first one that actually gets pushed.
Should fix an issue where we were turning something like:
push {r8, r4, r7, lr}
sub sp, #24
into nonsense like:
push {r2, r3, r4, r5, r6, r7, r8, r4, r7, lr}
llvm-svn: 285232
2016-10-26 20:01:00 +00:00
|
|
|
for (int i = MI->getNumOperands() - 1; i >= RegListIdx; --i) {
|
|
|
|
MachineOperand &MO = MI->getOperand(i);
|
|
|
|
RegList.push_back(MO);
|
|
|
|
|
2019-09-03 09:51:19 +00:00
|
|
|
if (MO.isReg() && !MO.isImplicit() &&
|
|
|
|
TRI->getEncodingValue(MO.getReg()) < FirstRegEnc)
|
ARM: don't rely on push/pop reglists being in order when folding SP adjust.
It would be a very nice invariant to rely on, but unfortunately it doesn't
necessarily hold (and the causes of mis-sorted reglists appear to be quite
varied) so to be robust the frame lowering code can't assume that the first
register in the list is also the first one that actually gets pushed.
Should fix an issue where we were turning something like:
push {r8, r4, r7, lr}
sub sp, #24
into nonsense like:
push {r2, r3, r4, r5, r6, r7, r8, r4, r7, lr}
llvm-svn: 285232
2016-10-26 20:01:00 +00:00
|
|
|
FirstRegEnc = TRI->getEncodingValue(MO.getReg());
|
|
|
|
}
|
|
|
|
|
2013-12-01 14:16:24 +00:00
|
|
|
const MCPhysReg *CSRegs = TRI->getCalleeSavedRegs(&MF);
|
2013-11-08 17:18:07 +00:00
|
|
|
|
|
|
|
// Now try to find enough space in the reglist to allocate NumBytes.
|
ARM: don't rely on push/pop reglists being in order when folding SP adjust.
It would be a very nice invariant to rely on, but unfortunately it doesn't
necessarily hold (and the causes of mis-sorted reglists appear to be quite
varied) so to be robust the frame lowering code can't assume that the first
register in the list is also the first one that actually gets pushed.
Should fix an issue where we were turning something like:
push {r8, r4, r7, lr}
sub sp, #24
into nonsense like:
push {r2, r3, r4, r5, r6, r7, r8, r4, r7, lr}
llvm-svn: 285232
2016-10-26 20:01:00 +00:00
|
|
|
for (int CurRegEnc = FirstRegEnc - 1; CurRegEnc >= 0 && RegsNeeded;
|
|
|
|
--CurRegEnc) {
|
|
|
|
unsigned CurReg = RegClass->getRegister(CurRegEnc);
|
2019-09-03 09:51:19 +00:00
|
|
|
if (IsT1PushPop && CurRegEnc > TRI->getEncodingValue(ARM::R7))
|
2019-04-01 23:55:57 +00:00
|
|
|
continue;
|
2013-11-08 17:18:07 +00:00
|
|
|
if (!IsPop) {
|
2018-01-08 14:47:19 +00:00
|
|
|
// Pushing any register is completely harmless, mark the register involved
|
|
|
|
// as undef since we don't care about its value and must not restore it
|
|
|
|
// during stack unwinding.
|
2013-11-08 17:18:07 +00:00
|
|
|
RegList.push_back(MachineOperand::CreateReg(CurReg, false, false,
|
|
|
|
false, false, true));
|
2013-12-01 14:16:24 +00:00
|
|
|
--RegsNeeded;
|
2013-11-08 17:18:07 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2013-12-01 14:16:24 +00:00
|
|
|
// However, we can only pop an extra register if it's not live. For
|
|
|
|
// registers live within the function we might clobber a return value
|
|
|
|
// register; the other way a register can be live here is if it's
|
|
|
|
// callee-saved.
|
|
|
|
if (isCalleeSavedRegister(CurReg, CSRegs) ||
|
2015-12-11 19:42:09 +00:00
|
|
|
MI->getParent()->computeRegisterLiveness(TRI, CurReg, MI) !=
|
|
|
|
MachineBasicBlock::LQR_Dead) {
|
2013-12-01 14:16:24 +00:00
|
|
|
// VFP pops don't allow holes in the register list, so any skip is fatal
|
|
|
|
// for our transformation. GPR pops do, so we should just keep looking.
|
|
|
|
if (IsVFPPushPop)
|
|
|
|
return false;
|
|
|
|
else
|
|
|
|
continue;
|
|
|
|
}
|
2013-11-08 17:18:07 +00:00
|
|
|
|
|
|
|
// Mark the unimportant registers as <def,dead> in the POP.
|
2013-11-22 00:46:32 +00:00
|
|
|
RegList.push_back(MachineOperand::CreateReg(CurReg, true, false, false,
|
|
|
|
true));
|
2013-12-01 14:16:24 +00:00
|
|
|
--RegsNeeded;
|
2013-11-08 17:18:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (RegsNeeded > 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Finally we know we can profitably perform the optimisation so go
|
|
|
|
// ahead: strip all existing registers off and add them back again
|
|
|
|
// in the right order.
|
|
|
|
for (int i = MI->getNumOperands() - 1; i >= RegListIdx; --i)
|
|
|
|
MI->RemoveOperand(i);
|
|
|
|
|
|
|
|
// Add the complete list back in.
|
|
|
|
MachineInstrBuilder MIB(MF, &*MI);
|
|
|
|
for (int i = RegList.size() - 1; i >= 0; --i)
|
2017-01-13 09:58:52 +00:00
|
|
|
MIB.add(RegList[i]);
|
2013-11-08 17:18:07 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-08-27 01:23:50 +00:00
|
|
|
bool llvm::rewriteARMFrameIndex(MachineInstr &MI, unsigned FrameRegIdx,
|
2020-04-07 17:28:53 -04:00
|
|
|
Register FrameReg, int &Offset,
|
2009-08-27 01:23:50 +00:00
|
|
|
const ARMBaseInstrInfo &TII) {
|
2009-07-28 05:48:47 +00:00
|
|
|
unsigned Opcode = MI.getOpcode();
|
2011-06-28 19:10:37 +00:00
|
|
|
const MCInstrDesc &Desc = MI.getDesc();
|
2009-07-28 05:48:47 +00:00
|
|
|
unsigned AddrMode = (Desc.TSFlags & ARMII::AddrModeMask);
|
|
|
|
bool isSub = false;
|
2009-08-11 15:33:49 +00:00
|
|
|
|
2009-07-28 05:48:47 +00:00
|
|
|
// Memory operands in inline assembly always use AddrMode2.
|
[ARM] additionally check for ARM::INLINEASM_BR w/ ARM::INLINEASM
Summary:
We were observing failures for arm32 allyesconfigs of the Linux kernel
with the asm goto Clang patch, where ldr's were being generated to
offsets too far away to encode in imm12.
It looks like since INLINEASM_BR was created off of INLINEASM, a few
checks for INLINEASM needed to be updated to check for either case.
pr/41999
Link: https://github.com/ClangBuiltLinux/linux/issues/490
Reviewers: peter.smith, kristof.beyls, ostannard, rengolin, t.p.northover
Reviewed By: peter.smith
Subscribers: jyu2, javed.absar, hiraditya, llvm-commits, nathanchance, craig.topper, kees, srhines
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D62400
llvm-svn: 361659
2019-05-24 18:58:21 +00:00
|
|
|
if (Opcode == ARM::INLINEASM || Opcode == ARM::INLINEASM_BR)
|
2009-07-28 05:48:47 +00:00
|
|
|
AddrMode = ARMII::AddrMode2;
|
2009-08-11 15:33:49 +00:00
|
|
|
|
2009-07-28 05:48:47 +00:00
|
|
|
if (Opcode == ARM::ADDri) {
|
|
|
|
Offset += MI.getOperand(FrameRegIdx+1).getImm();
|
|
|
|
if (Offset == 0) {
|
|
|
|
// Turn it into a move.
|
|
|
|
MI.setDesc(TII.get(ARM::MOVr));
|
|
|
|
MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
|
|
|
|
MI.RemoveOperand(FrameRegIdx+1);
|
2009-08-27 01:23:50 +00:00
|
|
|
Offset = 0;
|
|
|
|
return true;
|
2009-07-28 05:48:47 +00:00
|
|
|
} else if (Offset < 0) {
|
|
|
|
Offset = -Offset;
|
|
|
|
isSub = true;
|
|
|
|
MI.setDesc(TII.get(ARM::SUBri));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Common case: small offset, fits into instruction.
|
|
|
|
if (ARM_AM::getSOImmVal(Offset) != -1) {
|
|
|
|
// Replace the FrameIndex with sp / fp
|
|
|
|
MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
|
|
|
|
MI.getOperand(FrameRegIdx+1).ChangeToImmediate(Offset);
|
2009-08-27 01:23:50 +00:00
|
|
|
Offset = 0;
|
|
|
|
return true;
|
2009-07-28 05:48:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, pull as much of the immedidate into this ADDri/SUBri
|
|
|
|
// as possible.
|
|
|
|
unsigned RotAmt = ARM_AM::getSOImmValRotate(Offset);
|
|
|
|
unsigned ThisImmVal = Offset & ARM_AM::rotr32(0xFF, RotAmt);
|
|
|
|
|
|
|
|
// We will handle these bits from offset, clear them.
|
|
|
|
Offset &= ~ThisImmVal;
|
|
|
|
|
|
|
|
// Get the properly encoded SOImmVal field.
|
|
|
|
assert(ARM_AM::getSOImmVal(ThisImmVal) != -1 &&
|
|
|
|
"Bit extraction didn't work?");
|
|
|
|
MI.getOperand(FrameRegIdx+1).ChangeToImmediate(ThisImmVal);
|
|
|
|
} else {
|
|
|
|
unsigned ImmIdx = 0;
|
|
|
|
int InstrOffs = 0;
|
|
|
|
unsigned NumBits = 0;
|
|
|
|
unsigned Scale = 1;
|
|
|
|
switch (AddrMode) {
|
2017-01-26 23:40:06 +00:00
|
|
|
case ARMII::AddrMode_i12:
|
2010-10-26 22:37:02 +00:00
|
|
|
ImmIdx = FrameRegIdx + 1;
|
|
|
|
InstrOffs = MI.getOperand(ImmIdx).getImm();
|
|
|
|
NumBits = 12;
|
|
|
|
break;
|
2017-01-26 23:40:06 +00:00
|
|
|
case ARMII::AddrMode2:
|
2009-07-28 05:48:47 +00:00
|
|
|
ImmIdx = FrameRegIdx+2;
|
|
|
|
InstrOffs = ARM_AM::getAM2Offset(MI.getOperand(ImmIdx).getImm());
|
|
|
|
if (ARM_AM::getAM2Op(MI.getOperand(ImmIdx).getImm()) == ARM_AM::sub)
|
|
|
|
InstrOffs *= -1;
|
|
|
|
NumBits = 12;
|
|
|
|
break;
|
2017-01-26 23:40:06 +00:00
|
|
|
case ARMII::AddrMode3:
|
2009-07-28 05:48:47 +00:00
|
|
|
ImmIdx = FrameRegIdx+2;
|
|
|
|
InstrOffs = ARM_AM::getAM3Offset(MI.getOperand(ImmIdx).getImm());
|
|
|
|
if (ARM_AM::getAM3Op(MI.getOperand(ImmIdx).getImm()) == ARM_AM::sub)
|
|
|
|
InstrOffs *= -1;
|
|
|
|
NumBits = 8;
|
|
|
|
break;
|
2009-08-08 13:35:48 +00:00
|
|
|
case ARMII::AddrMode4:
|
2009-11-15 21:45:34 +00:00
|
|
|
case ARMII::AddrMode6:
|
2009-08-27 01:23:50 +00:00
|
|
|
// Can't fold any offset even if it's zero.
|
|
|
|
return false;
|
2017-01-26 23:40:06 +00:00
|
|
|
case ARMII::AddrMode5:
|
2009-07-28 05:48:47 +00:00
|
|
|
ImmIdx = FrameRegIdx+1;
|
|
|
|
InstrOffs = ARM_AM::getAM5Offset(MI.getOperand(ImmIdx).getImm());
|
|
|
|
if (ARM_AM::getAM5Op(MI.getOperand(ImmIdx).getImm()) == ARM_AM::sub)
|
|
|
|
InstrOffs *= -1;
|
|
|
|
NumBits = 8;
|
|
|
|
Scale = 4;
|
|
|
|
break;
|
[ARM] Armv8.2-A FP16 code generation (part 1/3)
This is the groundwork for Armv8.2-A FP16 code generation .
Clang passes and returns _Float16 values as floats, together with the required
bitconverts and truncs etc. to implement correct AAPCS behaviour, see D42318.
We will implement half-precision argument passing/returning lowering in the ARM
backend soon, but for now this means that this:
_Float16 sub(_Float16 a, _Float16 b) {
return a + b;
}
gets lowered to this:
define float @sub(float %a.coerce, float %b.coerce) {
entry:
%0 = bitcast float %a.coerce to i32
%tmp.0.extract.trunc = trunc i32 %0 to i16
%1 = bitcast i16 %tmp.0.extract.trunc to half
<SNIP>
%add = fadd half %1, %3
<SNIP>
}
When FullFP16 is *not* supported, we don't make f16 a legal type, and we get
legalization for "free", i.e. nothing changes and everything works as before.
And also f16 argument passing/returning is handled.
When FullFP16 is supported, we do make f16 a legal type, and have 2 places that
we need to patch up: f16 argument passing and returning, which involves minor
tweaks to avoid unnecessary code generation for some bitcasts.
As a "demonstrator" that this works for the different FP16, FullFP16, softfp
modes, etc., I've added match rules to the VSUB instruction description showing
that we can codegen this instruction from IR, but more importantly, also to
some conversion instructions. These conversions were causing issue before in
the FP16 and FullFP16 cases.
I've also added match rules to the VLDRH and VSTRH desriptions, so that we can
actually compile the entire half-precision sub code example above. This showed
that these loads and stores had the wrong addressing mode specified: AddrMode5
instead of AddrMode5FP16, which turned out not be implemented at all, so that
has also been added.
This is the minimal patch that shows all the different moving parts. In patch
2/3 I will add some efficient lowering of bitcasts, and in 2/3 I will add the
remaining Armv8.2-A FP16 instruction descriptions.
Thanks to Sam Parker and Oliver Stannard for their help and reviews!
Differential Revision: https://reviews.llvm.org/D38315
llvm-svn: 323512
2018-01-26 09:26:40 +00:00
|
|
|
case ARMII::AddrMode5FP16:
|
|
|
|
ImmIdx = FrameRegIdx+1;
|
|
|
|
InstrOffs = ARM_AM::getAM5Offset(MI.getOperand(ImmIdx).getImm());
|
|
|
|
if (ARM_AM::getAM5Op(MI.getOperand(ImmIdx).getImm()) == ARM_AM::sub)
|
|
|
|
InstrOffs *= -1;
|
|
|
|
NumBits = 8;
|
|
|
|
Scale = 2;
|
|
|
|
break;
|
[ARM] Add MVE vector load/store instructions.
This adds the rest of the vector memory access instructions. It
includes contiguous loads/stores, with an ordinary addressing mode
such as [r0,#offset] (plus writeback variants); gather loads and
scatter stores with a scalar base address register and a vector of
offsets from it (written [r0,q1] or similar); and gather/scatters with
a vector of base addresses (written [q0,#offset], again with
writeback). Additionally, some of the loads can widen each loaded
value into a larger vector lane, and the corresponding stores narrow
them again.
To implement these, we also have to add the addressing modes they
need. Also, in AsmParser, the `isMem` query function now has
subqueries `isGPRMem` and `isMVEMem`, according to which kind of base
register is used by a given memory access operand.
I've also had to add an extra check in `checkTargetMatchPredicate` in
the AsmParser, without which our last-minute check of `rGPR` register
operands against SP and PC was failing an assertion because Tablegen
had inserted an immediate 0 in place of one of a pair of tied register
operands. (This matches the way the corresponding check for `MCK_rGPR`
in `validateTargetOperandClass` is guarded.) Apparently the MVE load
instructions were the first to have ever triggered this assertion, but
I think only because they were the first to have a combination of the
usual Arm pre/post writeback system and the `rGPR` class in particular.
Reviewers: dmgreen, samparker, SjoerdMeijer, t.p.northover
Subscribers: javed.absar, kristof.beyls, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D62680
llvm-svn: 364291
2019-06-25 11:24:18 +00:00
|
|
|
case ARMII::AddrModeT2_i7:
|
|
|
|
case ARMII::AddrModeT2_i7s2:
|
[ARM] Add the non-MVE instructions in Arm v8.1-M.
This adds support for the new family of conditional selection /
increment / negation instructions; the low-overhead branch
instructions (e.g. BF, WLS, DLS); the CLRM instruction to zero a whole
list of registers at once; the new VMRS/VMSR and VLDR/VSTR
instructions to get data in and out of 8.1-M system registers,
particularly including the new VPR register used by MVE vector
predication.
To support this, we also add a register name 'zr' (used by the CSEL
family to force one of the inputs to the constant 0), and operand
types for lists of registers that are also allowed to include APSR or
VPR (used by CLRM). The VLDR/VSTR instructions also need a new
addressing mode.
The low-overhead branch instructions exist in their own separate
architecture extension, which we treat as enabled by default, but you
can say -mattr=-lob or equivalent to turn it off.
Reviewers: dmgreen, samparker, SjoerdMeijer, t.p.northover
Reviewed By: samparker
Subscribers: miyuki, javed.absar, kristof.beyls, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D62667
llvm-svn: 363039
2019-06-11 09:29:18 +00:00
|
|
|
case ARMII::AddrModeT2_i7s4:
|
|
|
|
ImmIdx = FrameRegIdx+1;
|
|
|
|
InstrOffs = MI.getOperand(ImmIdx).getImm();
|
|
|
|
NumBits = 7;
|
[ARM] Add MVE vector load/store instructions.
This adds the rest of the vector memory access instructions. It
includes contiguous loads/stores, with an ordinary addressing mode
such as [r0,#offset] (plus writeback variants); gather loads and
scatter stores with a scalar base address register and a vector of
offsets from it (written [r0,q1] or similar); and gather/scatters with
a vector of base addresses (written [q0,#offset], again with
writeback). Additionally, some of the loads can widen each loaded
value into a larger vector lane, and the corresponding stores narrow
them again.
To implement these, we also have to add the addressing modes they
need. Also, in AsmParser, the `isMem` query function now has
subqueries `isGPRMem` and `isMVEMem`, according to which kind of base
register is used by a given memory access operand.
I've also had to add an extra check in `checkTargetMatchPredicate` in
the AsmParser, without which our last-minute check of `rGPR` register
operands against SP and PC was failing an assertion because Tablegen
had inserted an immediate 0 in place of one of a pair of tied register
operands. (This matches the way the corresponding check for `MCK_rGPR`
in `validateTargetOperandClass` is guarded.) Apparently the MVE load
instructions were the first to have ever triggered this assertion, but
I think only because they were the first to have a combination of the
usual Arm pre/post writeback system and the `rGPR` class in particular.
Reviewers: dmgreen, samparker, SjoerdMeijer, t.p.northover
Subscribers: javed.absar, kristof.beyls, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D62680
llvm-svn: 364291
2019-06-25 11:24:18 +00:00
|
|
|
Scale = (AddrMode == ARMII::AddrModeT2_i7s2 ? 2 :
|
|
|
|
AddrMode == ARMII::AddrModeT2_i7s4 ? 4 : 1);
|
[ARM] Add the non-MVE instructions in Arm v8.1-M.
This adds support for the new family of conditional selection /
increment / negation instructions; the low-overhead branch
instructions (e.g. BF, WLS, DLS); the CLRM instruction to zero a whole
list of registers at once; the new VMRS/VMSR and VLDR/VSTR
instructions to get data in and out of 8.1-M system registers,
particularly including the new VPR register used by MVE vector
predication.
To support this, we also add a register name 'zr' (used by the CSEL
family to force one of the inputs to the constant 0), and operand
types for lists of registers that are also allowed to include APSR or
VPR (used by CLRM). The VLDR/VSTR instructions also need a new
addressing mode.
The low-overhead branch instructions exist in their own separate
architecture extension, which we treat as enabled by default, but you
can say -mattr=-lob or equivalent to turn it off.
Reviewers: dmgreen, samparker, SjoerdMeijer, t.p.northover
Reviewed By: samparker
Subscribers: miyuki, javed.absar, kristof.beyls, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D62667
llvm-svn: 363039
2019-06-11 09:29:18 +00:00
|
|
|
break;
|
2009-07-28 05:48:47 +00:00
|
|
|
default:
|
|
|
|
llvm_unreachable("Unsupported addressing mode!");
|
|
|
|
}
|
|
|
|
|
|
|
|
Offset += InstrOffs * Scale;
|
|
|
|
assert((Offset & (Scale-1)) == 0 && "Can't encode this offset!");
|
|
|
|
if (Offset < 0) {
|
|
|
|
Offset = -Offset;
|
|
|
|
isSub = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Attempt to fold address comp. if opcode has offset bits
|
|
|
|
if (NumBits > 0) {
|
|
|
|
// Common case: small offset, fits into instruction.
|
|
|
|
MachineOperand &ImmOp = MI.getOperand(ImmIdx);
|
|
|
|
int ImmedOffset = Offset / Scale;
|
|
|
|
unsigned Mask = (1 << NumBits) - 1;
|
|
|
|
if ((unsigned)Offset <= Mask * Scale) {
|
|
|
|
// Replace the FrameIndex with sp
|
|
|
|
MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
|
2010-10-27 01:19:41 +00:00
|
|
|
// FIXME: When addrmode2 goes away, this will simplify (like the
|
|
|
|
// T2 version), as the LDR.i12 versions don't need the encoding
|
|
|
|
// tricks for the offset value.
|
|
|
|
if (isSub) {
|
|
|
|
if (AddrMode == ARMII::AddrMode_i12)
|
|
|
|
ImmedOffset = -ImmedOffset;
|
|
|
|
else
|
|
|
|
ImmedOffset |= 1 << NumBits;
|
|
|
|
}
|
2009-07-28 05:48:47 +00:00
|
|
|
ImmOp.ChangeToImmediate(ImmedOffset);
|
2009-08-27 01:23:50 +00:00
|
|
|
Offset = 0;
|
|
|
|
return true;
|
2009-07-28 05:48:47 +00:00
|
|
|
}
|
2009-08-11 15:33:49 +00:00
|
|
|
|
2009-07-28 05:48:47 +00:00
|
|
|
// Otherwise, it didn't fit. Pull in what we can to simplify the immed.
|
|
|
|
ImmedOffset = ImmedOffset & Mask;
|
2010-10-27 16:50:31 +00:00
|
|
|
if (isSub) {
|
|
|
|
if (AddrMode == ARMII::AddrMode_i12)
|
|
|
|
ImmedOffset = -ImmedOffset;
|
|
|
|
else
|
|
|
|
ImmedOffset |= 1 << NumBits;
|
|
|
|
}
|
2009-07-28 05:48:47 +00:00
|
|
|
ImmOp.ChangeToImmediate(ImmedOffset);
|
|
|
|
Offset &= ~(Mask*Scale);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-27 01:23:50 +00:00
|
|
|
Offset = (isSub) ? -Offset : Offset;
|
|
|
|
return Offset == 0;
|
2009-07-28 05:48:47 +00:00
|
|
|
}
|
2010-08-06 01:32:48 +00:00
|
|
|
|
2012-06-29 21:33:59 +00:00
|
|
|
/// analyzeCompare - For a comparison instruction, return the source registers
|
|
|
|
/// in SrcReg and SrcReg2 if having two register operands, and the value it
|
|
|
|
/// compares against in CmpValue. Return true if the comparison instruction
|
|
|
|
/// can be analyzed.
|
2020-04-03 13:22:51 -04:00
|
|
|
bool ARMBaseInstrInfo::analyzeCompare(const MachineInstr &MI, Register &SrcReg,
|
|
|
|
Register &SrcReg2, int &CmpMask,
|
2016-06-30 00:01:54 +00:00
|
|
|
int &CmpValue) const {
|
|
|
|
switch (MI.getOpcode()) {
|
2010-08-06 01:32:48 +00:00
|
|
|
default: break;
|
2010-08-11 00:23:00 +00:00
|
|
|
case ARM::CMPri:
|
2010-08-06 01:32:48 +00:00
|
|
|
case ARM::t2CMPri:
|
2016-09-09 09:51:06 +00:00
|
|
|
case ARM::tCMPi8:
|
2016-06-30 00:01:54 +00:00
|
|
|
SrcReg = MI.getOperand(0).getReg();
|
2012-06-29 21:33:59 +00:00
|
|
|
SrcReg2 = 0;
|
2010-09-21 12:01:15 +00:00
|
|
|
CmpMask = ~0;
|
2016-06-30 00:01:54 +00:00
|
|
|
CmpValue = MI.getOperand(1).getImm();
|
2010-08-06 01:32:48 +00:00
|
|
|
return true;
|
2012-05-11 01:30:47 +00:00
|
|
|
case ARM::CMPrr:
|
|
|
|
case ARM::t2CMPrr:
|
2019-02-22 12:23:31 +00:00
|
|
|
case ARM::tCMPr:
|
2016-06-30 00:01:54 +00:00
|
|
|
SrcReg = MI.getOperand(0).getReg();
|
|
|
|
SrcReg2 = MI.getOperand(1).getReg();
|
2012-05-11 01:30:47 +00:00
|
|
|
CmpMask = ~0;
|
|
|
|
CmpValue = 0;
|
|
|
|
return true;
|
2010-09-21 12:01:15 +00:00
|
|
|
case ARM::TSTri:
|
|
|
|
case ARM::t2TSTri:
|
2016-06-30 00:01:54 +00:00
|
|
|
SrcReg = MI.getOperand(0).getReg();
|
2012-06-29 21:33:59 +00:00
|
|
|
SrcReg2 = 0;
|
2016-06-30 00:01:54 +00:00
|
|
|
CmpMask = MI.getOperand(1).getImm();
|
2010-09-21 12:01:15 +00:00
|
|
|
CmpValue = 0;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-09-29 10:12:08 +00:00
|
|
|
/// isSuitableForMask - Identify a suitable 'and' instruction that
|
|
|
|
/// operates on the given source register and applies the same mask
|
|
|
|
/// as a 'tst' instruction. Provide a limited look-through for copies.
|
|
|
|
/// When successful, MI will hold the found instruction.
|
2020-04-03 13:22:51 -04:00
|
|
|
static bool isSuitableForMask(MachineInstr *&MI, Register SrcReg,
|
2010-09-21 13:30:57 +00:00
|
|
|
int CmpMask, bool CommonUse) {
|
2010-09-29 10:12:08 +00:00
|
|
|
switch (MI->getOpcode()) {
|
2010-09-21 12:01:15 +00:00
|
|
|
case ARM::ANDri:
|
|
|
|
case ARM::t2ANDri:
|
2010-09-29 10:12:08 +00:00
|
|
|
if (CmpMask != MI->getOperand(2).getImm())
|
2010-09-21 13:30:57 +00:00
|
|
|
return false;
|
2010-09-29 10:12:08 +00:00
|
|
|
if (SrcReg == MI->getOperand(CommonUse ? 1 : 0).getReg())
|
2010-09-21 12:01:15 +00:00
|
|
|
return true;
|
|
|
|
break;
|
2010-08-06 01:32:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-01-17 19:19:05 +00:00
|
|
|
/// getCmpToAddCondition - assume the flags are set by CMP(a,b), return
|
|
|
|
/// the condition code if we modify the instructions such that flags are
|
|
|
|
/// set by ADD(a,b,X).
|
|
|
|
inline static ARMCC::CondCodes getCmpToAddCondition(ARMCC::CondCodes CC) {
|
|
|
|
switch (CC) {
|
|
|
|
default: return ARMCC::AL;
|
|
|
|
case ARMCC::HS: return ARMCC::LO;
|
|
|
|
case ARMCC::LO: return ARMCC::HS;
|
|
|
|
case ARMCC::VS: return ARMCC::VS;
|
|
|
|
case ARMCC::VC: return ARMCC::VC;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-29 22:06:19 +00:00
|
|
|
/// isRedundantFlagInstr - check whether the first instruction, whose only
|
|
|
|
/// purpose is to update flags, can be made redundant.
|
|
|
|
/// CMPrr can be made redundant by SUBrr if the operands are the same.
|
|
|
|
/// CMPri can be made redundant by SUBri if the operands are the same.
|
2018-01-17 19:19:05 +00:00
|
|
|
/// CMPrr(r0, r1) can be made redundant by ADDr[ri](r0, r1, X).
|
2012-06-29 22:06:19 +00:00
|
|
|
/// This function can be extended later on.
|
2018-01-17 19:19:05 +00:00
|
|
|
inline static bool isRedundantFlagInstr(const MachineInstr *CmpI,
|
2020-04-03 13:22:51 -04:00
|
|
|
Register SrcReg, Register SrcReg2,
|
2019-02-22 12:23:31 +00:00
|
|
|
int ImmValue, const MachineInstr *OI,
|
|
|
|
bool &IsThumb1) {
|
2019-02-07 10:51:04 +00:00
|
|
|
if ((CmpI->getOpcode() == ARM::CMPrr || CmpI->getOpcode() == ARM::t2CMPrr) &&
|
|
|
|
(OI->getOpcode() == ARM::SUBrr || OI->getOpcode() == ARM::t2SUBrr) &&
|
2012-06-29 22:06:19 +00:00
|
|
|
((OI->getOperand(1).getReg() == SrcReg &&
|
|
|
|
OI->getOperand(2).getReg() == SrcReg2) ||
|
|
|
|
(OI->getOperand(1).getReg() == SrcReg2 &&
|
2019-02-22 12:23:31 +00:00
|
|
|
OI->getOperand(2).getReg() == SrcReg))) {
|
|
|
|
IsThumb1 = false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (CmpI->getOpcode() == ARM::tCMPr && OI->getOpcode() == ARM::tSUBrr &&
|
|
|
|
((OI->getOperand(2).getReg() == SrcReg &&
|
|
|
|
OI->getOperand(3).getReg() == SrcReg2) ||
|
|
|
|
(OI->getOperand(2).getReg() == SrcReg2 &&
|
|
|
|
OI->getOperand(3).getReg() == SrcReg))) {
|
|
|
|
IsThumb1 = true;
|
2012-06-29 22:06:19 +00:00
|
|
|
return true;
|
2019-02-22 12:23:31 +00:00
|
|
|
}
|
2012-06-29 22:06:19 +00:00
|
|
|
|
2019-02-07 10:51:04 +00:00
|
|
|
if ((CmpI->getOpcode() == ARM::CMPri || CmpI->getOpcode() == ARM::t2CMPri) &&
|
|
|
|
(OI->getOpcode() == ARM::SUBri || OI->getOpcode() == ARM::t2SUBri) &&
|
2012-06-29 22:06:19 +00:00
|
|
|
OI->getOperand(1).getReg() == SrcReg &&
|
2019-02-22 12:23:31 +00:00
|
|
|
OI->getOperand(2).getImm() == ImmValue) {
|
|
|
|
IsThumb1 = false;
|
2012-06-29 22:06:19 +00:00
|
|
|
return true;
|
2019-02-22 12:23:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (CmpI->getOpcode() == ARM::tCMPi8 &&
|
|
|
|
(OI->getOpcode() == ARM::tSUBi8 || OI->getOpcode() == ARM::tSUBi3) &&
|
|
|
|
OI->getOperand(2).getReg() == SrcReg &&
|
|
|
|
OI->getOperand(3).getImm() == ImmValue) {
|
|
|
|
IsThumb1 = true;
|
|
|
|
return true;
|
|
|
|
}
|
2018-01-17 19:19:05 +00:00
|
|
|
|
|
|
|
if ((CmpI->getOpcode() == ARM::CMPrr || CmpI->getOpcode() == ARM::t2CMPrr) &&
|
|
|
|
(OI->getOpcode() == ARM::ADDrr || OI->getOpcode() == ARM::t2ADDrr ||
|
|
|
|
OI->getOpcode() == ARM::ADDri || OI->getOpcode() == ARM::t2ADDri) &&
|
2019-02-21 11:03:13 +00:00
|
|
|
OI->getOperand(0).isReg() && OI->getOperand(1).isReg() &&
|
2018-01-17 19:19:05 +00:00
|
|
|
OI->getOperand(0).getReg() == SrcReg &&
|
2019-02-22 12:23:31 +00:00
|
|
|
OI->getOperand(1).getReg() == SrcReg2) {
|
|
|
|
IsThumb1 = false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (CmpI->getOpcode() == ARM::tCMPr &&
|
|
|
|
(OI->getOpcode() == ARM::tADDi3 || OI->getOpcode() == ARM::tADDi8 ||
|
|
|
|
OI->getOpcode() == ARM::tADDrr) &&
|
|
|
|
OI->getOperand(0).getReg() == SrcReg &&
|
|
|
|
OI->getOperand(2).getReg() == SrcReg2) {
|
|
|
|
IsThumb1 = true;
|
2018-01-17 19:19:05 +00:00
|
|
|
return true;
|
2019-02-22 12:23:31 +00:00
|
|
|
}
|
|
|
|
|
2012-06-29 22:06:19 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-01-20 13:10:12 +00:00
|
|
|
static bool isOptimizeCompareCandidate(MachineInstr *MI, bool &IsThumb1) {
|
|
|
|
switch (MI->getOpcode()) {
|
|
|
|
default: return false;
|
|
|
|
case ARM::tLSLri:
|
|
|
|
case ARM::tLSRri:
|
|
|
|
case ARM::tLSLrr:
|
|
|
|
case ARM::tLSRrr:
|
|
|
|
case ARM::tSUBrr:
|
|
|
|
case ARM::tADDrr:
|
|
|
|
case ARM::tADDi3:
|
|
|
|
case ARM::tADDi8:
|
|
|
|
case ARM::tSUBi3:
|
|
|
|
case ARM::tSUBi8:
|
|
|
|
case ARM::tMUL:
|
2019-02-25 15:50:54 +00:00
|
|
|
case ARM::tADC:
|
|
|
|
case ARM::tSBC:
|
|
|
|
case ARM::tRSB:
|
|
|
|
case ARM::tAND:
|
|
|
|
case ARM::tORR:
|
|
|
|
case ARM::tEOR:
|
|
|
|
case ARM::tBIC:
|
|
|
|
case ARM::tMVN:
|
|
|
|
case ARM::tASRri:
|
|
|
|
case ARM::tASRrr:
|
|
|
|
case ARM::tROR:
|
2017-01-20 13:10:12 +00:00
|
|
|
IsThumb1 = true;
|
|
|
|
LLVM_FALLTHROUGH;
|
|
|
|
case ARM::RSBrr:
|
|
|
|
case ARM::RSBri:
|
|
|
|
case ARM::RSCrr:
|
|
|
|
case ARM::RSCri:
|
|
|
|
case ARM::ADDrr:
|
|
|
|
case ARM::ADDri:
|
|
|
|
case ARM::ADCrr:
|
|
|
|
case ARM::ADCri:
|
|
|
|
case ARM::SUBrr:
|
|
|
|
case ARM::SUBri:
|
|
|
|
case ARM::SBCrr:
|
|
|
|
case ARM::SBCri:
|
|
|
|
case ARM::t2RSBri:
|
|
|
|
case ARM::t2ADDrr:
|
|
|
|
case ARM::t2ADDri:
|
|
|
|
case ARM::t2ADCrr:
|
|
|
|
case ARM::t2ADCri:
|
|
|
|
case ARM::t2SUBrr:
|
|
|
|
case ARM::t2SUBri:
|
|
|
|
case ARM::t2SBCrr:
|
|
|
|
case ARM::t2SBCri:
|
|
|
|
case ARM::ANDrr:
|
|
|
|
case ARM::ANDri:
|
|
|
|
case ARM::t2ANDrr:
|
|
|
|
case ARM::t2ANDri:
|
|
|
|
case ARM::ORRrr:
|
|
|
|
case ARM::ORRri:
|
|
|
|
case ARM::t2ORRrr:
|
|
|
|
case ARM::t2ORRri:
|
|
|
|
case ARM::EORrr:
|
|
|
|
case ARM::EORri:
|
|
|
|
case ARM::t2EORrr:
|
|
|
|
case ARM::t2EORri:
|
|
|
|
case ARM::t2LSRri:
|
|
|
|
case ARM::t2LSRrr:
|
|
|
|
case ARM::t2LSLri:
|
|
|
|
case ARM::t2LSLrr:
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-29 21:33:59 +00:00
|
|
|
/// optimizeCompareInstr - Convert the instruction supplying the argument to the
|
|
|
|
/// comparison into one that sets the zero bit in the flags register;
|
|
|
|
/// Remove a redundant Compare instruction if an earlier instruction can set the
|
|
|
|
/// flags in the same way as Compare.
|
|
|
|
/// E.g. SUBrr(r1,r2) and CMPrr(r1,r2). We also handle the case where two
|
|
|
|
/// operands are swapped: SUBrr(r1,r2) and CMPrr(r2,r1), by updating the
|
|
|
|
/// condition code of instructions which use the flags.
|
2016-06-30 00:01:54 +00:00
|
|
|
bool ARMBaseInstrInfo::optimizeCompareInstr(
|
2020-04-03 13:22:51 -04:00
|
|
|
MachineInstr &CmpInstr, Register SrcReg, Register SrcReg2, int CmpMask,
|
2016-06-30 00:01:54 +00:00
|
|
|
int CmpValue, const MachineRegisterInfo *MRI) const {
|
2012-06-29 22:06:19 +00:00
|
|
|
// Get the unique definition of SrcReg.
|
|
|
|
MachineInstr *MI = MRI->getUniqueVRegDef(SrcReg);
|
|
|
|
if (!MI) return false;
|
2010-09-10 23:34:19 +00:00
|
|
|
|
2010-09-21 12:01:15 +00:00
|
|
|
// Masked compares sometimes use the same register as the corresponding 'and'.
|
|
|
|
if (CmpMask != ~0) {
|
2016-02-23 02:46:52 +00:00
|
|
|
if (!isSuitableForMask(MI, SrcReg, CmpMask, false) || isPredicated(*MI)) {
|
2014-04-25 05:30:21 +00:00
|
|
|
MI = nullptr;
|
2014-03-13 23:12:04 +00:00
|
|
|
for (MachineRegisterInfo::use_instr_iterator
|
|
|
|
UI = MRI->use_instr_begin(SrcReg), UE = MRI->use_instr_end();
|
|
|
|
UI != UE; ++UI) {
|
2016-06-30 00:01:54 +00:00
|
|
|
if (UI->getParent() != CmpInstr.getParent())
|
|
|
|
continue;
|
2010-09-29 10:12:08 +00:00
|
|
|
MachineInstr *PotentialAND = &*UI;
|
2012-09-10 19:17:25 +00:00
|
|
|
if (!isSuitableForMask(PotentialAND, SrcReg, CmpMask, true) ||
|
2016-02-23 02:46:52 +00:00
|
|
|
isPredicated(*PotentialAND))
|
2010-09-21 12:01:15 +00:00
|
|
|
continue;
|
2010-09-29 10:12:08 +00:00
|
|
|
MI = PotentialAND;
|
2010-09-21 12:01:15 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!MI) return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-11 01:30:47 +00:00
|
|
|
// Get ready to iterate backward from CmpInstr.
|
|
|
|
MachineBasicBlock::iterator I = CmpInstr, E = MI,
|
2016-06-30 00:01:54 +00:00
|
|
|
B = CmpInstr.getParent()->begin();
|
2010-10-09 00:03:48 +00:00
|
|
|
|
|
|
|
// Early exit if CmpInstr is at the beginning of the BB.
|
|
|
|
if (I == B) return false;
|
|
|
|
|
2012-05-11 01:30:47 +00:00
|
|
|
// There are two possible candidates which can be changed to set CPSR:
|
2018-01-17 19:19:05 +00:00
|
|
|
// One is MI, the other is a SUB or ADD instruction.
|
|
|
|
// For CMPrr(r1,r2), we are looking for SUB(r1,r2), SUB(r2,r1), or
|
|
|
|
// ADDr[ri](r1, r2, X).
|
2012-05-11 01:30:47 +00:00
|
|
|
// For CMPri(r1, CmpValue), we are looking for SUBri(r1, CmpValue).
|
2018-01-17 19:19:05 +00:00
|
|
|
MachineInstr *SubAdd = nullptr;
|
2012-06-29 21:33:59 +00:00
|
|
|
if (SrcReg2 != 0)
|
2012-05-11 01:30:47 +00:00
|
|
|
// MI is not a candidate for CMPrr.
|
2014-04-25 05:30:21 +00:00
|
|
|
MI = nullptr;
|
2016-06-30 00:01:54 +00:00
|
|
|
else if (MI->getParent() != CmpInstr.getParent() || CmpValue != 0) {
|
2012-05-11 01:30:47 +00:00
|
|
|
// Conservatively refuse to convert an instruction which isn't in the same
|
|
|
|
// BB as the comparison.
|
2018-01-17 19:19:05 +00:00
|
|
|
// For CMPri w/ CmpValue != 0, a SubAdd may still be a candidate.
|
2015-02-02 16:56:50 +00:00
|
|
|
// Thus we cannot return here.
|
2016-06-30 00:01:54 +00:00
|
|
|
if (CmpInstr.getOpcode() == ARM::CMPri ||
|
2019-02-22 12:23:31 +00:00
|
|
|
CmpInstr.getOpcode() == ARM::t2CMPri ||
|
|
|
|
CmpInstr.getOpcode() == ARM::tCMPi8)
|
2014-04-25 05:30:21 +00:00
|
|
|
MI = nullptr;
|
2012-05-11 01:30:47 +00:00
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-01-20 13:10:12 +00:00
|
|
|
bool IsThumb1 = false;
|
|
|
|
if (MI && !isOptimizeCompareCandidate(MI, IsThumb1))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// We also want to do this peephole for cases like this: if (a*b == 0),
|
|
|
|
// and optimise away the CMP instruction from the generated code sequence:
|
|
|
|
// MULS, MOVS, MOVS, CMP. Here the MOVS instructions load the boolean values
|
|
|
|
// resulting from the select instruction, but these MOVS instructions for
|
|
|
|
// Thumb1 (V6M) are flag setting and are thus preventing this optimisation.
|
|
|
|
// However, if we only have MOVS instructions in between the CMP and the
|
|
|
|
// other instruction (the MULS in this example), then the CPSR is dead so we
|
|
|
|
// can safely reorder the sequence into: MOVS, MOVS, MULS, CMP. We do this
|
|
|
|
// reordering and then continue the analysis hoping we can eliminate the
|
|
|
|
// CMP. This peephole works on the vregs, so is still in SSA form. As a
|
|
|
|
// consequence, the movs won't redefine/kill the MUL operands which would
|
|
|
|
// make this reordering illegal.
|
2019-02-25 15:50:54 +00:00
|
|
|
const TargetRegisterInfo *TRI = &getRegisterInfo();
|
2017-01-20 13:10:12 +00:00
|
|
|
if (MI && IsThumb1) {
|
|
|
|
--I;
|
2019-02-25 15:50:54 +00:00
|
|
|
if (I != E && !MI->readsRegister(ARM::CPSR, TRI)) {
|
|
|
|
bool CanReorder = true;
|
|
|
|
for (; I != E; --I) {
|
|
|
|
if (I->getOpcode() != ARM::tMOVi8) {
|
|
|
|
CanReorder = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (CanReorder) {
|
|
|
|
MI = MI->removeFromParent();
|
|
|
|
E = CmpInstr;
|
|
|
|
CmpInstr.getParent()->insert(E, MI);
|
2017-01-20 13:10:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
I = CmpInstr;
|
|
|
|
E = MI;
|
|
|
|
}
|
|
|
|
|
2012-05-11 01:30:47 +00:00
|
|
|
// Check that CPSR isn't set between the comparison instruction and the one we
|
2018-01-17 19:19:05 +00:00
|
|
|
// want to change. At the same time, search for SubAdd.
|
2019-02-22 12:23:31 +00:00
|
|
|
bool SubAddIsThumb1 = false;
|
2018-01-22 17:53:47 +00:00
|
|
|
do {
|
|
|
|
const MachineInstr &Instr = *--I;
|
2010-08-06 01:32:48 +00:00
|
|
|
|
2018-01-17 19:19:05 +00:00
|
|
|
// Check whether CmpInstr can be made redundant by the current instruction.
|
2019-02-22 12:23:31 +00:00
|
|
|
if (isRedundantFlagInstr(&CmpInstr, SrcReg, SrcReg2, CmpValue, &Instr,
|
|
|
|
SubAddIsThumb1)) {
|
2018-01-17 19:19:05 +00:00
|
|
|
SubAdd = &*I;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-01-22 17:53:47 +00:00
|
|
|
// Allow E (which was initially MI) to be SubAdd but do not search before E.
|
|
|
|
if (I == E)
|
|
|
|
break;
|
|
|
|
|
2012-06-29 22:06:19 +00:00
|
|
|
if (Instr.modifiesRegister(ARM::CPSR, TRI) ||
|
|
|
|
Instr.readsRegister(ARM::CPSR, TRI))
|
When we look at instructions to convert to setting the 's' flag, we need to look
at more than those which define CPSR. You can have this situation:
(1) subs ...
(2) sub r6, r5, r4
(3) movge ...
(4) cmp r6, 0
(5) movge ...
We cannot convert (2) to "subs" because (3) is using the CPSR set by
(1). There's an analogous situation here:
(1) sub r1, r2, r3
(2) sub r4, r5, r6
(3) cmp r4, ...
(5) movge ...
(6) cmp r1, ...
(7) movge ...
We cannot convert (1) to "subs" because of the intervening use of CPSR.
llvm-svn: 117950
2010-11-01 20:41:43 +00:00
|
|
|
// This instruction modifies or uses CPSR after the one we want to
|
|
|
|
// change. We can't do this transformation.
|
2012-06-29 22:06:19 +00:00
|
|
|
return false;
|
2012-05-11 01:30:47 +00:00
|
|
|
|
2019-03-22 20:49:15 +00:00
|
|
|
if (I == B) {
|
|
|
|
// In some cases, we scan the use-list of an instruction for an AND;
|
|
|
|
// that AND is in the same BB, but may not be scheduled before the
|
|
|
|
// corresponding TST. In that case, bail out.
|
|
|
|
//
|
|
|
|
// FIXME: We could try to reschedule the AND.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} while (true);
|
2010-08-06 01:32:48 +00:00
|
|
|
|
2012-05-11 01:30:47 +00:00
|
|
|
// Return false if no candidates exist.
|
2018-01-17 19:19:05 +00:00
|
|
|
if (!MI && !SubAdd)
|
2012-05-11 01:30:47 +00:00
|
|
|
return false;
|
|
|
|
|
2019-02-14 11:09:24 +00:00
|
|
|
// If we found a SubAdd, use it as it will be closer to the CMP
|
|
|
|
if (SubAdd) {
|
|
|
|
MI = SubAdd;
|
2019-02-22 12:23:31 +00:00
|
|
|
IsThumb1 = SubAddIsThumb1;
|
2019-02-14 11:09:24 +00:00
|
|
|
}
|
2012-05-11 01:30:47 +00:00
|
|
|
|
2012-09-10 19:17:25 +00:00
|
|
|
// We can't use a predicated instruction - it doesn't always write the flags.
|
2016-02-23 02:46:52 +00:00
|
|
|
if (isPredicated(*MI))
|
2012-09-10 19:17:25 +00:00
|
|
|
return false;
|
|
|
|
|
2017-01-20 13:10:12 +00:00
|
|
|
// Scan forward for the use of CPSR
|
|
|
|
// When checking against MI: if it's a conditional code that requires
|
|
|
|
// checking of the V bit or C bit, then this is not safe to do.
|
|
|
|
// It is safe to remove CmpInstr if CPSR is redefined or killed.
|
|
|
|
// If we are done with the basic block, we need to check whether CPSR is
|
|
|
|
// live-out.
|
|
|
|
SmallVector<std::pair<MachineOperand*, ARMCC::CondCodes>, 4>
|
|
|
|
OperandsToUpdate;
|
|
|
|
bool isSafe = false;
|
|
|
|
I = CmpInstr;
|
|
|
|
E = CmpInstr.getParent()->end();
|
|
|
|
while (!isSafe && ++I != E) {
|
|
|
|
const MachineInstr &Instr = *I;
|
|
|
|
for (unsigned IO = 0, EO = Instr.getNumOperands();
|
|
|
|
!isSafe && IO != EO; ++IO) {
|
|
|
|
const MachineOperand &MO = Instr.getOperand(IO);
|
|
|
|
if (MO.isRegMask() && MO.clobbersPhysReg(ARM::CPSR)) {
|
|
|
|
isSafe = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!MO.isReg() || MO.getReg() != ARM::CPSR)
|
|
|
|
continue;
|
|
|
|
if (MO.isDef()) {
|
|
|
|
isSafe = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Condition code is after the operand before CPSR except for VSELs.
|
|
|
|
ARMCC::CondCodes CC;
|
|
|
|
bool IsInstrVSel = true;
|
|
|
|
switch (Instr.getOpcode()) {
|
|
|
|
default:
|
|
|
|
IsInstrVSel = false;
|
|
|
|
CC = (ARMCC::CondCodes)Instr.getOperand(IO - 1).getImm();
|
|
|
|
break;
|
|
|
|
case ARM::VSELEQD:
|
|
|
|
case ARM::VSELEQS:
|
2019-09-03 10:53:07 +00:00
|
|
|
case ARM::VSELEQH:
|
2017-01-20 13:10:12 +00:00
|
|
|
CC = ARMCC::EQ;
|
|
|
|
break;
|
|
|
|
case ARM::VSELGTD:
|
|
|
|
case ARM::VSELGTS:
|
2019-09-03 10:53:07 +00:00
|
|
|
case ARM::VSELGTH:
|
2017-01-20 13:10:12 +00:00
|
|
|
CC = ARMCC::GT;
|
|
|
|
break;
|
|
|
|
case ARM::VSELGED:
|
|
|
|
case ARM::VSELGES:
|
2019-09-03 10:53:07 +00:00
|
|
|
case ARM::VSELGEH:
|
2017-01-20 13:10:12 +00:00
|
|
|
CC = ARMCC::GE;
|
|
|
|
break;
|
|
|
|
case ARM::VSELVSD:
|
2019-09-03 10:53:07 +00:00
|
|
|
case ARM::VSELVSS:
|
|
|
|
case ARM::VSELVSH:
|
2017-01-20 13:10:12 +00:00
|
|
|
CC = ARMCC::VS;
|
|
|
|
break;
|
|
|
|
}
|
2013-12-06 17:56:48 +00:00
|
|
|
|
2018-01-17 19:19:05 +00:00
|
|
|
if (SubAdd) {
|
2017-01-20 13:10:12 +00:00
|
|
|
// If we have SUB(r1, r2) and CMP(r2, r1), the condition code based
|
|
|
|
// on CMP needs to be updated to be based on SUB.
|
2018-01-17 19:19:05 +00:00
|
|
|
// If we have ADD(r1, r2, X) and CMP(r1, r2), the condition code also
|
|
|
|
// needs to be modified.
|
2017-01-20 13:10:12 +00:00
|
|
|
// Push the condition code operands to OperandsToUpdate.
|
|
|
|
// If it is safe to remove CmpInstr, the condition code of these
|
|
|
|
// operands will be modified.
|
2018-01-17 19:19:05 +00:00
|
|
|
unsigned Opc = SubAdd->getOpcode();
|
|
|
|
bool IsSub = Opc == ARM::SUBrr || Opc == ARM::t2SUBrr ||
|
2019-02-22 12:23:31 +00:00
|
|
|
Opc == ARM::SUBri || Opc == ARM::t2SUBri ||
|
|
|
|
Opc == ARM::tSUBrr || Opc == ARM::tSUBi3 ||
|
|
|
|
Opc == ARM::tSUBi8;
|
|
|
|
unsigned OpI = Opc != ARM::tSUBrr ? 1 : 2;
|
|
|
|
if (!IsSub ||
|
|
|
|
(SrcReg2 != 0 && SubAdd->getOperand(OpI).getReg() == SrcReg2 &&
|
|
|
|
SubAdd->getOperand(OpI + 1).getReg() == SrcReg)) {
|
2017-01-20 13:10:12 +00:00
|
|
|
// VSel doesn't support condition code update.
|
|
|
|
if (IsInstrVSel)
|
2012-05-11 01:30:47 +00:00
|
|
|
return false;
|
2018-01-17 19:19:05 +00:00
|
|
|
// Ensure we can swap the condition.
|
|
|
|
ARMCC::CondCodes NewCC = (IsSub ? getSwappedCondition(CC) : getCmpToAddCondition(CC));
|
|
|
|
if (NewCC == ARMCC::AL)
|
|
|
|
return false;
|
2017-01-20 13:10:12 +00:00
|
|
|
OperandsToUpdate.push_back(
|
|
|
|
std::make_pair(&((*I).getOperand(IO - 1)), NewCC));
|
2015-02-02 16:56:50 +00:00
|
|
|
}
|
2017-01-20 13:10:12 +00:00
|
|
|
} else {
|
2018-01-17 19:19:05 +00:00
|
|
|
// No SubAdd, so this is x = <op> y, z; cmp x, 0.
|
2017-01-20 13:10:12 +00:00
|
|
|
switch (CC) {
|
|
|
|
case ARMCC::EQ: // Z
|
|
|
|
case ARMCC::NE: // Z
|
|
|
|
case ARMCC::MI: // N
|
|
|
|
case ARMCC::PL: // N
|
|
|
|
case ARMCC::AL: // none
|
|
|
|
// CPSR can be used multiple times, we should continue.
|
|
|
|
break;
|
|
|
|
case ARMCC::HS: // C
|
|
|
|
case ARMCC::LO: // C
|
|
|
|
case ARMCC::VS: // V
|
|
|
|
case ARMCC::VC: // V
|
|
|
|
case ARMCC::HI: // C Z
|
|
|
|
case ARMCC::LS: // C Z
|
|
|
|
case ARMCC::GE: // N V
|
|
|
|
case ARMCC::LT: // N V
|
|
|
|
case ARMCC::GT: // Z N V
|
|
|
|
case ARMCC::LE: // Z N V
|
|
|
|
// The instruction uses the V bit or C bit which is not safe.
|
2012-07-11 22:51:44 +00:00
|
|
|
return false;
|
2017-01-20 13:10:12 +00:00
|
|
|
}
|
|
|
|
}
|
2012-07-11 22:51:44 +00:00
|
|
|
}
|
2017-01-20 13:10:12 +00:00
|
|
|
}
|
2011-03-23 22:52:04 +00:00
|
|
|
|
2017-01-20 13:10:12 +00:00
|
|
|
// If CPSR is not killed nor re-defined, we should check whether it is
|
|
|
|
// live-out. If it is live-out, do not optimize.
|
|
|
|
if (!isSafe) {
|
|
|
|
MachineBasicBlock *MBB = CmpInstr.getParent();
|
|
|
|
for (MachineBasicBlock::succ_iterator SI = MBB->succ_begin(),
|
|
|
|
SE = MBB->succ_end(); SI != SE; ++SI)
|
|
|
|
if ((*SI)->isLiveIn(ARM::CPSR))
|
|
|
|
return false;
|
2010-08-06 01:32:48 +00:00
|
|
|
}
|
2017-01-20 13:10:12 +00:00
|
|
|
|
|
|
|
// Toggle the optional operand to CPSR (if it exists - in Thumb1 we always
|
|
|
|
// set CPSR so this is represented as an explicit output)
|
|
|
|
if (!IsThumb1) {
|
|
|
|
MI->getOperand(5).setReg(ARM::CPSR);
|
|
|
|
MI->getOperand(5).setIsDef(true);
|
2011-04-15 20:45:00 +00:00
|
|
|
}
|
2017-01-20 13:10:12 +00:00
|
|
|
assert(!isPredicated(*MI) && "Can't use flags from predicated instruction");
|
|
|
|
CmpInstr.eraseFromParent();
|
|
|
|
|
|
|
|
// Modify the condition code of operands in OperandsToUpdate.
|
|
|
|
// Since we have SUB(r1, r2) and CMP(r2, r1), the condition code needs to
|
|
|
|
// be changed from r2 > r1 to r1 < r2, from r2 < r1 to r1 > r2, etc.
|
|
|
|
for (unsigned i = 0, e = OperandsToUpdate.size(); i < e; i++)
|
|
|
|
OperandsToUpdate[i].first->setImm(OperandsToUpdate[i].second);
|
|
|
|
|
2018-10-26 19:32:24 +00:00
|
|
|
MI->clearRegisterDeads(ARM::CPSR);
|
|
|
|
|
2017-01-20 13:10:12 +00:00
|
|
|
return true;
|
2010-08-06 01:32:48 +00:00
|
|
|
}
|
2010-09-09 18:18:55 +00:00
|
|
|
|
2018-01-17 19:19:05 +00:00
|
|
|
bool ARMBaseInstrInfo::shouldSink(const MachineInstr &MI) const {
|
|
|
|
// Do not sink MI if it might be used to optimize a redundant compare.
|
|
|
|
// We heuristically only look at the instruction immediately following MI to
|
|
|
|
// avoid potentially searching the entire basic block.
|
|
|
|
if (isPredicated(MI))
|
|
|
|
return true;
|
|
|
|
MachineBasicBlock::const_iterator Next = &MI;
|
|
|
|
++Next;
|
2020-04-03 13:22:51 -04:00
|
|
|
Register SrcReg, SrcReg2;
|
2018-01-17 19:19:05 +00:00
|
|
|
int CmpMask, CmpValue;
|
2019-02-22 12:23:31 +00:00
|
|
|
bool IsThumb1;
|
2018-01-17 19:19:05 +00:00
|
|
|
if (Next != MI.getParent()->end() &&
|
|
|
|
analyzeCompare(*Next, SrcReg, SrcReg2, CmpMask, CmpValue) &&
|
2019-02-22 12:23:31 +00:00
|
|
|
isRedundantFlagInstr(&*Next, SrcReg, SrcReg2, CmpValue, &MI, IsThumb1))
|
2018-01-17 19:19:05 +00:00
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
bool ARMBaseInstrInfo::FoldImmediate(MachineInstr &UseMI, MachineInstr &DefMI,
|
2020-04-03 13:22:51 -04:00
|
|
|
Register Reg,
|
2010-11-17 20:13:28 +00:00
|
|
|
MachineRegisterInfo *MRI) const {
|
|
|
|
// Fold large immediates into add, sub, or, xor.
|
2016-06-30 00:01:54 +00:00
|
|
|
unsigned DefOpc = DefMI.getOpcode();
|
2010-11-17 20:13:28 +00:00
|
|
|
if (DefOpc != ARM::t2MOVi32imm && DefOpc != ARM::MOVi32imm)
|
|
|
|
return false;
|
2016-06-30 00:01:54 +00:00
|
|
|
if (!DefMI.getOperand(1).isImm())
|
2017-12-14 10:03:09 +00:00
|
|
|
// Could be t2MOVi32imm @xx
|
2010-11-17 20:13:28 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!MRI->hasOneNonDBGUse(Reg))
|
|
|
|
return false;
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
const MCInstrDesc &DefMCID = DefMI.getDesc();
|
ARM has a peephole optimization which looks for a def / use pair. The def
produces a 32-bit immediate which is consumed by the use. It tries to
fold the immediate by breaking it into two parts and fold them into the
immmediate fields of two uses. e.g
movw r2, #40885
movt r3, #46540
add r0, r0, r3
=>
add.w r0, r0, #3019898880
add.w r0, r0, #30146560
;
However, this transformation is incorrect if the user produces a flag. e.g.
movw r2, #40885
movt r3, #46540
adds r0, r0, r3
=>
add.w r0, r0, #3019898880
adds.w r0, r0, #30146560
Note the adds.w may not set the carry flag even if the original sequence
would.
rdar://11116189
llvm-svn: 153484
2012-03-26 23:31:00 +00:00
|
|
|
if (DefMCID.hasOptionalDef()) {
|
|
|
|
unsigned NumOps = DefMCID.getNumOperands();
|
2016-06-30 00:01:54 +00:00
|
|
|
const MachineOperand &MO = DefMI.getOperand(NumOps - 1);
|
ARM has a peephole optimization which looks for a def / use pair. The def
produces a 32-bit immediate which is consumed by the use. It tries to
fold the immediate by breaking it into two parts and fold them into the
immmediate fields of two uses. e.g
movw r2, #40885
movt r3, #46540
add r0, r0, r3
=>
add.w r0, r0, #3019898880
add.w r0, r0, #30146560
;
However, this transformation is incorrect if the user produces a flag. e.g.
movw r2, #40885
movt r3, #46540
adds r0, r0, r3
=>
add.w r0, r0, #3019898880
adds.w r0, r0, #30146560
Note the adds.w may not set the carry flag even if the original sequence
would.
rdar://11116189
llvm-svn: 153484
2012-03-26 23:31:00 +00:00
|
|
|
if (MO.getReg() == ARM::CPSR && !MO.isDead())
|
|
|
|
// If DefMI defines CPSR and it is not dead, it's obviously not safe
|
|
|
|
// to delete DefMI.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
const MCInstrDesc &UseMCID = UseMI.getDesc();
|
ARM has a peephole optimization which looks for a def / use pair. The def
produces a 32-bit immediate which is consumed by the use. It tries to
fold the immediate by breaking it into two parts and fold them into the
immmediate fields of two uses. e.g
movw r2, #40885
movt r3, #46540
add r0, r0, r3
=>
add.w r0, r0, #3019898880
add.w r0, r0, #30146560
;
However, this transformation is incorrect if the user produces a flag. e.g.
movw r2, #40885
movt r3, #46540
adds r0, r0, r3
=>
add.w r0, r0, #3019898880
adds.w r0, r0, #30146560
Note the adds.w may not set the carry flag even if the original sequence
would.
rdar://11116189
llvm-svn: 153484
2012-03-26 23:31:00 +00:00
|
|
|
if (UseMCID.hasOptionalDef()) {
|
|
|
|
unsigned NumOps = UseMCID.getNumOperands();
|
2016-06-30 00:01:54 +00:00
|
|
|
if (UseMI.getOperand(NumOps - 1).getReg() == ARM::CPSR)
|
ARM has a peephole optimization which looks for a def / use pair. The def
produces a 32-bit immediate which is consumed by the use. It tries to
fold the immediate by breaking it into two parts and fold them into the
immmediate fields of two uses. e.g
movw r2, #40885
movt r3, #46540
add r0, r0, r3
=>
add.w r0, r0, #3019898880
add.w r0, r0, #30146560
;
However, this transformation is incorrect if the user produces a flag. e.g.
movw r2, #40885
movt r3, #46540
adds r0, r0, r3
=>
add.w r0, r0, #3019898880
adds.w r0, r0, #30146560
Note the adds.w may not set the carry flag even if the original sequence
would.
rdar://11116189
llvm-svn: 153484
2012-03-26 23:31:00 +00:00
|
|
|
// If the instruction sets the flag, do not attempt this optimization
|
|
|
|
// since it may change the semantics of the code.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
unsigned UseOpc = UseMI.getOpcode();
|
2010-11-18 01:43:23 +00:00
|
|
|
unsigned NewUseOpc = 0;
|
2016-06-30 00:01:54 +00:00
|
|
|
uint32_t ImmVal = (uint32_t)DefMI.getOperand(1).getImm();
|
2010-11-18 01:43:23 +00:00
|
|
|
uint32_t SOImmValV1 = 0, SOImmValV2 = 0;
|
2010-11-17 20:13:28 +00:00
|
|
|
bool Commute = false;
|
|
|
|
switch (UseOpc) {
|
|
|
|
default: return false;
|
|
|
|
case ARM::SUBrr:
|
|
|
|
case ARM::ADDrr:
|
|
|
|
case ARM::ORRrr:
|
|
|
|
case ARM::EORrr:
|
|
|
|
case ARM::t2SUBrr:
|
|
|
|
case ARM::t2ADDrr:
|
|
|
|
case ARM::t2ORRrr:
|
|
|
|
case ARM::t2EORrr: {
|
2016-06-30 00:01:54 +00:00
|
|
|
Commute = UseMI.getOperand(2).getReg() != Reg;
|
2010-11-17 20:13:28 +00:00
|
|
|
switch (UseOpc) {
|
|
|
|
default: break;
|
2016-05-02 18:30:08 +00:00
|
|
|
case ARM::ADDrr:
|
2017-01-26 23:40:06 +00:00
|
|
|
case ARM::SUBrr:
|
2016-05-02 18:30:08 +00:00
|
|
|
if (UseOpc == ARM::SUBrr && Commute)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// ADD/SUB are special because they're essentially the same operation, so
|
|
|
|
// we can handle a larger range of immediates.
|
|
|
|
if (ARM_AM::isSOImmTwoPartVal(ImmVal))
|
|
|
|
NewUseOpc = UseOpc == ARM::ADDrr ? ARM::ADDri : ARM::SUBri;
|
|
|
|
else if (ARM_AM::isSOImmTwoPartVal(-ImmVal)) {
|
|
|
|
ImmVal = -ImmVal;
|
|
|
|
NewUseOpc = UseOpc == ARM::ADDrr ? ARM::SUBri : ARM::ADDri;
|
|
|
|
} else
|
2010-11-17 20:13:28 +00:00
|
|
|
return false;
|
2016-05-02 18:30:08 +00:00
|
|
|
SOImmValV1 = (uint32_t)ARM_AM::getSOImmTwoPartFirst(ImmVal);
|
|
|
|
SOImmValV2 = (uint32_t)ARM_AM::getSOImmTwoPartSecond(ImmVal);
|
|
|
|
break;
|
2010-11-17 20:13:28 +00:00
|
|
|
case ARM::ORRrr:
|
2017-01-26 23:40:06 +00:00
|
|
|
case ARM::EORrr:
|
2010-11-17 20:13:28 +00:00
|
|
|
if (!ARM_AM::isSOImmTwoPartVal(ImmVal))
|
|
|
|
return false;
|
|
|
|
SOImmValV1 = (uint32_t)ARM_AM::getSOImmTwoPartFirst(ImmVal);
|
|
|
|
SOImmValV2 = (uint32_t)ARM_AM::getSOImmTwoPartSecond(ImmVal);
|
|
|
|
switch (UseOpc) {
|
|
|
|
default: break;
|
|
|
|
case ARM::ORRrr: NewUseOpc = ARM::ORRri; break;
|
|
|
|
case ARM::EORrr: NewUseOpc = ARM::EORri; break;
|
|
|
|
}
|
|
|
|
break;
|
2016-05-02 18:30:08 +00:00
|
|
|
case ARM::t2ADDrr:
|
[ARM][Thumb2] Fix ADD/SUB invalid writes to SP
Summary:
This patch fixes pr23772 [ARM] r226200 can emit illegal thumb2 instruction: "sub sp, r12, #80".
The violation was that SUB and ADD (reg, immediate) instructions can only write to SP if the source register is also SP. So the above instructions was unpredictable.
To enforce that the instruction t2(ADD|SUB)ri does not write to SP we now enforce the destination register to be rGPR (That exclude PC and SP).
Different than the ARM specification, that defines one instruction that can read from SP, and one that can't, here we inserted one that can't write to SP, and other that can only write to SP as to reuse most of the hard-coded size optimizations.
When performing this change, it uncovered that emitting Thumb2 Reg plus Immediate could not emit all variants of ADD SP, SP #imm instructions before so it was refactored to be able to. (see test/CodeGen/Thumb2/mve-stacksplot.mir where we use a subw sp, sp, Imm12 variant )
It also uncovered a disassembly issue of adr.w instructions, that were only written as SUBW instructions (see llvm/test/MC/Disassembler/ARM/thumb2.txt).
Reviewers: eli.friedman, dmgreen, carwil, olista01, efriedma, andreadb
Reviewed By: efriedma
Subscribers: gbedwell, john.brawn, efriedma, ostannard, kristof.beyls, hiraditya, dmgreen, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D70680
2020-01-13 11:36:02 +00:00
|
|
|
case ARM::t2SUBrr: {
|
2016-05-02 18:30:08 +00:00
|
|
|
if (UseOpc == ARM::t2SUBrr && Commute)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// ADD/SUB are special because they're essentially the same operation, so
|
|
|
|
// we can handle a larger range of immediates.
|
[ARM][Thumb2] Fix ADD/SUB invalid writes to SP
Summary:
This patch fixes pr23772 [ARM] r226200 can emit illegal thumb2 instruction: "sub sp, r12, #80".
The violation was that SUB and ADD (reg, immediate) instructions can only write to SP if the source register is also SP. So the above instructions was unpredictable.
To enforce that the instruction t2(ADD|SUB)ri does not write to SP we now enforce the destination register to be rGPR (That exclude PC and SP).
Different than the ARM specification, that defines one instruction that can read from SP, and one that can't, here we inserted one that can't write to SP, and other that can only write to SP as to reuse most of the hard-coded size optimizations.
When performing this change, it uncovered that emitting Thumb2 Reg plus Immediate could not emit all variants of ADD SP, SP #imm instructions before so it was refactored to be able to. (see test/CodeGen/Thumb2/mve-stacksplot.mir where we use a subw sp, sp, Imm12 variant )
It also uncovered a disassembly issue of adr.w instructions, that were only written as SUBW instructions (see llvm/test/MC/Disassembler/ARM/thumb2.txt).
Reviewers: eli.friedman, dmgreen, carwil, olista01, efriedma, andreadb
Reviewed By: efriedma
Subscribers: gbedwell, john.brawn, efriedma, ostannard, kristof.beyls, hiraditya, dmgreen, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D70680
2020-01-13 11:36:02 +00:00
|
|
|
const bool ToSP = DefMI.getOperand(0).getReg() == ARM::SP;
|
|
|
|
const unsigned t2ADD = ToSP ? ARM::t2ADDspImm : ARM::t2ADDri;
|
|
|
|
const unsigned t2SUB = ToSP ? ARM::t2SUBspImm : ARM::t2SUBri;
|
2016-05-02 18:30:08 +00:00
|
|
|
if (ARM_AM::isT2SOImmTwoPartVal(ImmVal))
|
[ARM][Thumb2] Fix ADD/SUB invalid writes to SP
Summary:
This patch fixes pr23772 [ARM] r226200 can emit illegal thumb2 instruction: "sub sp, r12, #80".
The violation was that SUB and ADD (reg, immediate) instructions can only write to SP if the source register is also SP. So the above instructions was unpredictable.
To enforce that the instruction t2(ADD|SUB)ri does not write to SP we now enforce the destination register to be rGPR (That exclude PC and SP).
Different than the ARM specification, that defines one instruction that can read from SP, and one that can't, here we inserted one that can't write to SP, and other that can only write to SP as to reuse most of the hard-coded size optimizations.
When performing this change, it uncovered that emitting Thumb2 Reg plus Immediate could not emit all variants of ADD SP, SP #imm instructions before so it was refactored to be able to. (see test/CodeGen/Thumb2/mve-stacksplot.mir where we use a subw sp, sp, Imm12 variant )
It also uncovered a disassembly issue of adr.w instructions, that were only written as SUBW instructions (see llvm/test/MC/Disassembler/ARM/thumb2.txt).
Reviewers: eli.friedman, dmgreen, carwil, olista01, efriedma, andreadb
Reviewed By: efriedma
Subscribers: gbedwell, john.brawn, efriedma, ostannard, kristof.beyls, hiraditya, dmgreen, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D70680
2020-01-13 11:36:02 +00:00
|
|
|
NewUseOpc = UseOpc == ARM::t2ADDrr ? t2ADD : t2SUB;
|
2016-05-02 18:30:08 +00:00
|
|
|
else if (ARM_AM::isT2SOImmTwoPartVal(-ImmVal)) {
|
|
|
|
ImmVal = -ImmVal;
|
[ARM][Thumb2] Fix ADD/SUB invalid writes to SP
Summary:
This patch fixes pr23772 [ARM] r226200 can emit illegal thumb2 instruction: "sub sp, r12, #80".
The violation was that SUB and ADD (reg, immediate) instructions can only write to SP if the source register is also SP. So the above instructions was unpredictable.
To enforce that the instruction t2(ADD|SUB)ri does not write to SP we now enforce the destination register to be rGPR (That exclude PC and SP).
Different than the ARM specification, that defines one instruction that can read from SP, and one that can't, here we inserted one that can't write to SP, and other that can only write to SP as to reuse most of the hard-coded size optimizations.
When performing this change, it uncovered that emitting Thumb2 Reg plus Immediate could not emit all variants of ADD SP, SP #imm instructions before so it was refactored to be able to. (see test/CodeGen/Thumb2/mve-stacksplot.mir where we use a subw sp, sp, Imm12 variant )
It also uncovered a disassembly issue of adr.w instructions, that were only written as SUBW instructions (see llvm/test/MC/Disassembler/ARM/thumb2.txt).
Reviewers: eli.friedman, dmgreen, carwil, olista01, efriedma, andreadb
Reviewed By: efriedma
Subscribers: gbedwell, john.brawn, efriedma, ostannard, kristof.beyls, hiraditya, dmgreen, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D70680
2020-01-13 11:36:02 +00:00
|
|
|
NewUseOpc = UseOpc == ARM::t2ADDrr ? t2SUB : t2ADD;
|
2016-05-02 18:30:08 +00:00
|
|
|
} else
|
2010-11-17 20:13:28 +00:00
|
|
|
return false;
|
2016-05-02 18:30:08 +00:00
|
|
|
SOImmValV1 = (uint32_t)ARM_AM::getT2SOImmTwoPartFirst(ImmVal);
|
|
|
|
SOImmValV2 = (uint32_t)ARM_AM::getT2SOImmTwoPartSecond(ImmVal);
|
|
|
|
break;
|
[ARM][Thumb2] Fix ADD/SUB invalid writes to SP
Summary:
This patch fixes pr23772 [ARM] r226200 can emit illegal thumb2 instruction: "sub sp, r12, #80".
The violation was that SUB and ADD (reg, immediate) instructions can only write to SP if the source register is also SP. So the above instructions was unpredictable.
To enforce that the instruction t2(ADD|SUB)ri does not write to SP we now enforce the destination register to be rGPR (That exclude PC and SP).
Different than the ARM specification, that defines one instruction that can read from SP, and one that can't, here we inserted one that can't write to SP, and other that can only write to SP as to reuse most of the hard-coded size optimizations.
When performing this change, it uncovered that emitting Thumb2 Reg plus Immediate could not emit all variants of ADD SP, SP #imm instructions before so it was refactored to be able to. (see test/CodeGen/Thumb2/mve-stacksplot.mir where we use a subw sp, sp, Imm12 variant )
It also uncovered a disassembly issue of adr.w instructions, that were only written as SUBW instructions (see llvm/test/MC/Disassembler/ARM/thumb2.txt).
Reviewers: eli.friedman, dmgreen, carwil, olista01, efriedma, andreadb
Reviewed By: efriedma
Subscribers: gbedwell, john.brawn, efriedma, ostannard, kristof.beyls, hiraditya, dmgreen, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D70680
2020-01-13 11:36:02 +00:00
|
|
|
}
|
2010-11-17 20:13:28 +00:00
|
|
|
case ARM::t2ORRrr:
|
2017-01-26 23:40:06 +00:00
|
|
|
case ARM::t2EORrr:
|
2010-11-17 20:13:28 +00:00
|
|
|
if (!ARM_AM::isT2SOImmTwoPartVal(ImmVal))
|
|
|
|
return false;
|
|
|
|
SOImmValV1 = (uint32_t)ARM_AM::getT2SOImmTwoPartFirst(ImmVal);
|
|
|
|
SOImmValV2 = (uint32_t)ARM_AM::getT2SOImmTwoPartSecond(ImmVal);
|
|
|
|
switch (UseOpc) {
|
|
|
|
default: break;
|
|
|
|
case ARM::t2ORRrr: NewUseOpc = ARM::t2ORRri; break;
|
|
|
|
case ARM::t2EORrr: NewUseOpc = ARM::t2EORri; break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned OpIdx = Commute ? 2 : 1;
|
Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Partial reverts in:
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
X86FixupLEAs.cpp - Some functions return unsigned and arguably should be MCRegister
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
HexagonBitSimplify.cpp - Function takes BitTracker::RegisterRef which appears to be unsigned&
MachineVerifier.cpp - Ambiguous operator==() given MCRegister and const Register
PPCFastISel.cpp - No Register::operator-=()
PeepholeOptimizer.cpp - TargetInstrInfo::optimizeLoadInstr() takes an unsigned&
MachineTraceMetrics.cpp - MachineTraceMetrics lacks a suitable constructor
Manual fixups in:
ARMFastISel.cpp - ARMEmitLoad() now takes a Register& instead of unsigned&
HexagonSplitDouble.cpp - Ternary operator was ambiguous between unsigned/Register
HexagonConstExtenders.cpp - Has a local class named Register, used llvm::Register instead of Register.
PPCFastISel.cpp - PPCEmitLoad() now takes a Register& instead of unsigned&
Depends on D65919
Reviewers: arsenm, bogner, craig.topper, RKSimon
Reviewed By: arsenm
Subscribers: RKSimon, craig.topper, lenary, aemerson, wuzish, jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65962
llvm-svn: 369041
2019-08-15 19:22:08 +00:00
|
|
|
Register Reg1 = UseMI.getOperand(OpIdx).getReg();
|
2016-06-30 00:01:54 +00:00
|
|
|
bool isKill = UseMI.getOperand(OpIdx).isKill();
|
[ARM][Thumb2] Fix ADD/SUB invalid writes to SP
Summary:
This patch fixes pr23772 [ARM] r226200 can emit illegal thumb2 instruction: "sub sp, r12, #80".
The violation was that SUB and ADD (reg, immediate) instructions can only write to SP if the source register is also SP. So the above instructions was unpredictable.
To enforce that the instruction t2(ADD|SUB)ri does not write to SP we now enforce the destination register to be rGPR (That exclude PC and SP).
Different than the ARM specification, that defines one instruction that can read from SP, and one that can't, here we inserted one that can't write to SP, and other that can only write to SP as to reuse most of the hard-coded size optimizations.
When performing this change, it uncovered that emitting Thumb2 Reg plus Immediate could not emit all variants of ADD SP, SP #imm instructions before so it was refactored to be able to. (see test/CodeGen/Thumb2/mve-stacksplot.mir where we use a subw sp, sp, Imm12 variant )
It also uncovered a disassembly issue of adr.w instructions, that were only written as SUBW instructions (see llvm/test/MC/Disassembler/ARM/thumb2.txt).
Reviewers: eli.friedman, dmgreen, carwil, olista01, efriedma, andreadb
Reviewed By: efriedma
Subscribers: gbedwell, john.brawn, efriedma, ostannard, kristof.beyls, hiraditya, dmgreen, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D70680
2020-01-13 11:36:02 +00:00
|
|
|
const TargetRegisterClass *TRC = MRI->getRegClass(Reg);
|
|
|
|
Register NewReg = MRI->createVirtualRegister(TRC);
|
2017-01-13 10:18:01 +00:00
|
|
|
BuildMI(*UseMI.getParent(), UseMI, UseMI.getDebugLoc(), get(NewUseOpc),
|
|
|
|
NewReg)
|
|
|
|
.addReg(Reg1, getKillRegState(isKill))
|
|
|
|
.addImm(SOImmValV1)
|
|
|
|
.add(predOps(ARMCC::AL))
|
|
|
|
.add(condCodeOp());
|
2016-06-30 00:01:54 +00:00
|
|
|
UseMI.setDesc(get(NewUseOpc));
|
|
|
|
UseMI.getOperand(1).setReg(NewReg);
|
|
|
|
UseMI.getOperand(1).setIsKill();
|
|
|
|
UseMI.getOperand(2).ChangeToImmediate(SOImmValV2);
|
|
|
|
DefMI.eraseFromParent();
|
[ARM][Thumb2] Fix ADD/SUB invalid writes to SP
Summary:
This patch fixes pr23772 [ARM] r226200 can emit illegal thumb2 instruction: "sub sp, r12, #80".
The violation was that SUB and ADD (reg, immediate) instructions can only write to SP if the source register is also SP. So the above instructions was unpredictable.
To enforce that the instruction t2(ADD|SUB)ri does not write to SP we now enforce the destination register to be rGPR (That exclude PC and SP).
Different than the ARM specification, that defines one instruction that can read from SP, and one that can't, here we inserted one that can't write to SP, and other that can only write to SP as to reuse most of the hard-coded size optimizations.
When performing this change, it uncovered that emitting Thumb2 Reg plus Immediate could not emit all variants of ADD SP, SP #imm instructions before so it was refactored to be able to. (see test/CodeGen/Thumb2/mve-stacksplot.mir where we use a subw sp, sp, Imm12 variant )
It also uncovered a disassembly issue of adr.w instructions, that were only written as SUBW instructions (see llvm/test/MC/Disassembler/ARM/thumb2.txt).
Reviewers: eli.friedman, dmgreen, carwil, olista01, efriedma, andreadb
Reviewed By: efriedma
Subscribers: gbedwell, john.brawn, efriedma, ostannard, kristof.beyls, hiraditya, dmgreen, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D70680
2020-01-13 11:36:02 +00:00
|
|
|
// FIXME: t2ADDrr should be split, as different rulles apply when writing to SP.
|
|
|
|
// Just as t2ADDri, that was split to [t2ADDri, t2ADDspImm].
|
|
|
|
// Then the below code will not be needed, as the input/output register
|
|
|
|
// classes will be rgpr or gprSP.
|
|
|
|
// For now, we fix the UseMI operand explicitly here:
|
|
|
|
switch(NewUseOpc){
|
|
|
|
case ARM::t2ADDspImm:
|
|
|
|
case ARM::t2SUBspImm:
|
|
|
|
case ARM::t2ADDri:
|
|
|
|
case ARM::t2SUBri:
|
|
|
|
MRI->setRegClass(UseMI.getOperand(0).getReg(), TRC);
|
|
|
|
}
|
2010-11-17 20:13:28 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-09-29 21:43:49 +00:00
|
|
|
static unsigned getNumMicroOpsSwiftLdSt(const InstrItineraryData *ItinData,
|
2016-06-30 00:01:54 +00:00
|
|
|
const MachineInstr &MI) {
|
|
|
|
switch (MI.getOpcode()) {
|
2012-09-29 21:43:49 +00:00
|
|
|
default: {
|
2016-06-30 00:01:54 +00:00
|
|
|
const MCInstrDesc &Desc = MI.getDesc();
|
2012-09-29 21:43:49 +00:00
|
|
|
int UOps = ItinData->getNumMicroOps(Desc.getSchedClass());
|
|
|
|
assert(UOps >= 0 && "bad # UOps");
|
|
|
|
return UOps;
|
|
|
|
}
|
|
|
|
|
|
|
|
case ARM::LDRrs:
|
|
|
|
case ARM::LDRBrs:
|
|
|
|
case ARM::STRrs:
|
|
|
|
case ARM::STRBrs: {
|
2016-06-30 00:01:54 +00:00
|
|
|
unsigned ShOpVal = MI.getOperand(3).getImm();
|
2012-09-29 21:43:49 +00:00
|
|
|
bool isSub = ARM_AM::getAM2Op(ShOpVal) == ARM_AM::sub;
|
|
|
|
unsigned ShImm = ARM_AM::getAM2Offset(ShOpVal);
|
|
|
|
if (!isSub &&
|
|
|
|
(ShImm == 0 ||
|
|
|
|
((ShImm == 1 || ShImm == 2 || ShImm == 3) &&
|
|
|
|
ARM_AM::getAM2ShiftOpc(ShOpVal) == ARM_AM::lsl)))
|
|
|
|
return 1;
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
case ARM::LDRH:
|
|
|
|
case ARM::STRH: {
|
2016-06-30 00:01:54 +00:00
|
|
|
if (!MI.getOperand(2).getReg())
|
2012-09-29 21:43:49 +00:00
|
|
|
return 1;
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
unsigned ShOpVal = MI.getOperand(3).getImm();
|
2012-09-29 21:43:49 +00:00
|
|
|
bool isSub = ARM_AM::getAM2Op(ShOpVal) == ARM_AM::sub;
|
|
|
|
unsigned ShImm = ARM_AM::getAM2Offset(ShOpVal);
|
|
|
|
if (!isSub &&
|
|
|
|
(ShImm == 0 ||
|
|
|
|
((ShImm == 1 || ShImm == 2 || ShImm == 3) &&
|
|
|
|
ARM_AM::getAM2ShiftOpc(ShOpVal) == ARM_AM::lsl)))
|
|
|
|
return 1;
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
case ARM::LDRSB:
|
|
|
|
case ARM::LDRSH:
|
2016-06-30 00:01:54 +00:00
|
|
|
return (ARM_AM::getAM3Op(MI.getOperand(3).getImm()) == ARM_AM::sub) ? 3 : 2;
|
2012-09-29 21:43:49 +00:00
|
|
|
|
|
|
|
case ARM::LDRSB_POST:
|
|
|
|
case ARM::LDRSH_POST: {
|
Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Partial reverts in:
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
X86FixupLEAs.cpp - Some functions return unsigned and arguably should be MCRegister
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
HexagonBitSimplify.cpp - Function takes BitTracker::RegisterRef which appears to be unsigned&
MachineVerifier.cpp - Ambiguous operator==() given MCRegister and const Register
PPCFastISel.cpp - No Register::operator-=()
PeepholeOptimizer.cpp - TargetInstrInfo::optimizeLoadInstr() takes an unsigned&
MachineTraceMetrics.cpp - MachineTraceMetrics lacks a suitable constructor
Manual fixups in:
ARMFastISel.cpp - ARMEmitLoad() now takes a Register& instead of unsigned&
HexagonSplitDouble.cpp - Ternary operator was ambiguous between unsigned/Register
HexagonConstExtenders.cpp - Has a local class named Register, used llvm::Register instead of Register.
PPCFastISel.cpp - PPCEmitLoad() now takes a Register& instead of unsigned&
Depends on D65919
Reviewers: arsenm, bogner, craig.topper, RKSimon
Reviewed By: arsenm
Subscribers: RKSimon, craig.topper, lenary, aemerson, wuzish, jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65962
llvm-svn: 369041
2019-08-15 19:22:08 +00:00
|
|
|
Register Rt = MI.getOperand(0).getReg();
|
|
|
|
Register Rm = MI.getOperand(3).getReg();
|
2012-09-29 21:43:49 +00:00
|
|
|
return (Rt == Rm) ? 4 : 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
case ARM::LDR_PRE_REG:
|
|
|
|
case ARM::LDRB_PRE_REG: {
|
Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Partial reverts in:
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
X86FixupLEAs.cpp - Some functions return unsigned and arguably should be MCRegister
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
HexagonBitSimplify.cpp - Function takes BitTracker::RegisterRef which appears to be unsigned&
MachineVerifier.cpp - Ambiguous operator==() given MCRegister and const Register
PPCFastISel.cpp - No Register::operator-=()
PeepholeOptimizer.cpp - TargetInstrInfo::optimizeLoadInstr() takes an unsigned&
MachineTraceMetrics.cpp - MachineTraceMetrics lacks a suitable constructor
Manual fixups in:
ARMFastISel.cpp - ARMEmitLoad() now takes a Register& instead of unsigned&
HexagonSplitDouble.cpp - Ternary operator was ambiguous between unsigned/Register
HexagonConstExtenders.cpp - Has a local class named Register, used llvm::Register instead of Register.
PPCFastISel.cpp - PPCEmitLoad() now takes a Register& instead of unsigned&
Depends on D65919
Reviewers: arsenm, bogner, craig.topper, RKSimon
Reviewed By: arsenm
Subscribers: RKSimon, craig.topper, lenary, aemerson, wuzish, jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65962
llvm-svn: 369041
2019-08-15 19:22:08 +00:00
|
|
|
Register Rt = MI.getOperand(0).getReg();
|
|
|
|
Register Rm = MI.getOperand(3).getReg();
|
2012-09-29 21:43:49 +00:00
|
|
|
if (Rt == Rm)
|
|
|
|
return 3;
|
2016-06-30 00:01:54 +00:00
|
|
|
unsigned ShOpVal = MI.getOperand(4).getImm();
|
2012-09-29 21:43:49 +00:00
|
|
|
bool isSub = ARM_AM::getAM2Op(ShOpVal) == ARM_AM::sub;
|
|
|
|
unsigned ShImm = ARM_AM::getAM2Offset(ShOpVal);
|
|
|
|
if (!isSub &&
|
|
|
|
(ShImm == 0 ||
|
|
|
|
((ShImm == 1 || ShImm == 2 || ShImm == 3) &&
|
|
|
|
ARM_AM::getAM2ShiftOpc(ShOpVal) == ARM_AM::lsl)))
|
|
|
|
return 2;
|
|
|
|
return 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
case ARM::STR_PRE_REG:
|
|
|
|
case ARM::STRB_PRE_REG: {
|
2016-06-30 00:01:54 +00:00
|
|
|
unsigned ShOpVal = MI.getOperand(4).getImm();
|
2012-09-29 21:43:49 +00:00
|
|
|
bool isSub = ARM_AM::getAM2Op(ShOpVal) == ARM_AM::sub;
|
|
|
|
unsigned ShImm = ARM_AM::getAM2Offset(ShOpVal);
|
|
|
|
if (!isSub &&
|
|
|
|
(ShImm == 0 ||
|
|
|
|
((ShImm == 1 || ShImm == 2 || ShImm == 3) &&
|
|
|
|
ARM_AM::getAM2ShiftOpc(ShOpVal) == ARM_AM::lsl)))
|
|
|
|
return 2;
|
|
|
|
return 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
case ARM::LDRH_PRE:
|
|
|
|
case ARM::STRH_PRE: {
|
Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Partial reverts in:
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
X86FixupLEAs.cpp - Some functions return unsigned and arguably should be MCRegister
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
HexagonBitSimplify.cpp - Function takes BitTracker::RegisterRef which appears to be unsigned&
MachineVerifier.cpp - Ambiguous operator==() given MCRegister and const Register
PPCFastISel.cpp - No Register::operator-=()
PeepholeOptimizer.cpp - TargetInstrInfo::optimizeLoadInstr() takes an unsigned&
MachineTraceMetrics.cpp - MachineTraceMetrics lacks a suitable constructor
Manual fixups in:
ARMFastISel.cpp - ARMEmitLoad() now takes a Register& instead of unsigned&
HexagonSplitDouble.cpp - Ternary operator was ambiguous between unsigned/Register
HexagonConstExtenders.cpp - Has a local class named Register, used llvm::Register instead of Register.
PPCFastISel.cpp - PPCEmitLoad() now takes a Register& instead of unsigned&
Depends on D65919
Reviewers: arsenm, bogner, craig.topper, RKSimon
Reviewed By: arsenm
Subscribers: RKSimon, craig.topper, lenary, aemerson, wuzish, jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65962
llvm-svn: 369041
2019-08-15 19:22:08 +00:00
|
|
|
Register Rt = MI.getOperand(0).getReg();
|
|
|
|
Register Rm = MI.getOperand(3).getReg();
|
2012-09-29 21:43:49 +00:00
|
|
|
if (!Rm)
|
|
|
|
return 2;
|
|
|
|
if (Rt == Rm)
|
|
|
|
return 3;
|
2016-06-30 00:01:54 +00:00
|
|
|
return (ARM_AM::getAM3Op(MI.getOperand(4).getImm()) == ARM_AM::sub) ? 3 : 2;
|
2012-09-29 21:43:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
case ARM::LDR_POST_REG:
|
|
|
|
case ARM::LDRB_POST_REG:
|
|
|
|
case ARM::LDRH_POST: {
|
Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Partial reverts in:
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
X86FixupLEAs.cpp - Some functions return unsigned and arguably should be MCRegister
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
HexagonBitSimplify.cpp - Function takes BitTracker::RegisterRef which appears to be unsigned&
MachineVerifier.cpp - Ambiguous operator==() given MCRegister and const Register
PPCFastISel.cpp - No Register::operator-=()
PeepholeOptimizer.cpp - TargetInstrInfo::optimizeLoadInstr() takes an unsigned&
MachineTraceMetrics.cpp - MachineTraceMetrics lacks a suitable constructor
Manual fixups in:
ARMFastISel.cpp - ARMEmitLoad() now takes a Register& instead of unsigned&
HexagonSplitDouble.cpp - Ternary operator was ambiguous between unsigned/Register
HexagonConstExtenders.cpp - Has a local class named Register, used llvm::Register instead of Register.
PPCFastISel.cpp - PPCEmitLoad() now takes a Register& instead of unsigned&
Depends on D65919
Reviewers: arsenm, bogner, craig.topper, RKSimon
Reviewed By: arsenm
Subscribers: RKSimon, craig.topper, lenary, aemerson, wuzish, jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65962
llvm-svn: 369041
2019-08-15 19:22:08 +00:00
|
|
|
Register Rt = MI.getOperand(0).getReg();
|
|
|
|
Register Rm = MI.getOperand(3).getReg();
|
2012-09-29 21:43:49 +00:00
|
|
|
return (Rt == Rm) ? 3 : 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
case ARM::LDR_PRE_IMM:
|
|
|
|
case ARM::LDRB_PRE_IMM:
|
|
|
|
case ARM::LDR_POST_IMM:
|
|
|
|
case ARM::LDRB_POST_IMM:
|
|
|
|
case ARM::STRB_POST_IMM:
|
|
|
|
case ARM::STRB_POST_REG:
|
|
|
|
case ARM::STRB_PRE_IMM:
|
|
|
|
case ARM::STRH_POST:
|
|
|
|
case ARM::STR_POST_IMM:
|
|
|
|
case ARM::STR_POST_REG:
|
|
|
|
case ARM::STR_PRE_IMM:
|
|
|
|
return 2;
|
|
|
|
|
|
|
|
case ARM::LDRSB_PRE:
|
|
|
|
case ARM::LDRSH_PRE: {
|
Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Partial reverts in:
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
X86FixupLEAs.cpp - Some functions return unsigned and arguably should be MCRegister
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
HexagonBitSimplify.cpp - Function takes BitTracker::RegisterRef which appears to be unsigned&
MachineVerifier.cpp - Ambiguous operator==() given MCRegister and const Register
PPCFastISel.cpp - No Register::operator-=()
PeepholeOptimizer.cpp - TargetInstrInfo::optimizeLoadInstr() takes an unsigned&
MachineTraceMetrics.cpp - MachineTraceMetrics lacks a suitable constructor
Manual fixups in:
ARMFastISel.cpp - ARMEmitLoad() now takes a Register& instead of unsigned&
HexagonSplitDouble.cpp - Ternary operator was ambiguous between unsigned/Register
HexagonConstExtenders.cpp - Has a local class named Register, used llvm::Register instead of Register.
PPCFastISel.cpp - PPCEmitLoad() now takes a Register& instead of unsigned&
Depends on D65919
Reviewers: arsenm, bogner, craig.topper, RKSimon
Reviewed By: arsenm
Subscribers: RKSimon, craig.topper, lenary, aemerson, wuzish, jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65962
llvm-svn: 369041
2019-08-15 19:22:08 +00:00
|
|
|
Register Rm = MI.getOperand(3).getReg();
|
2012-09-29 21:43:49 +00:00
|
|
|
if (Rm == 0)
|
|
|
|
return 3;
|
Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Partial reverts in:
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
X86FixupLEAs.cpp - Some functions return unsigned and arguably should be MCRegister
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
HexagonBitSimplify.cpp - Function takes BitTracker::RegisterRef which appears to be unsigned&
MachineVerifier.cpp - Ambiguous operator==() given MCRegister and const Register
PPCFastISel.cpp - No Register::operator-=()
PeepholeOptimizer.cpp - TargetInstrInfo::optimizeLoadInstr() takes an unsigned&
MachineTraceMetrics.cpp - MachineTraceMetrics lacks a suitable constructor
Manual fixups in:
ARMFastISel.cpp - ARMEmitLoad() now takes a Register& instead of unsigned&
HexagonSplitDouble.cpp - Ternary operator was ambiguous between unsigned/Register
HexagonConstExtenders.cpp - Has a local class named Register, used llvm::Register instead of Register.
PPCFastISel.cpp - PPCEmitLoad() now takes a Register& instead of unsigned&
Depends on D65919
Reviewers: arsenm, bogner, craig.topper, RKSimon
Reviewed By: arsenm
Subscribers: RKSimon, craig.topper, lenary, aemerson, wuzish, jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65962
llvm-svn: 369041
2019-08-15 19:22:08 +00:00
|
|
|
Register Rt = MI.getOperand(0).getReg();
|
2012-09-29 21:43:49 +00:00
|
|
|
if (Rt == Rm)
|
|
|
|
return 4;
|
2016-06-30 00:01:54 +00:00
|
|
|
unsigned ShOpVal = MI.getOperand(4).getImm();
|
2012-09-29 21:43:49 +00:00
|
|
|
bool isSub = ARM_AM::getAM2Op(ShOpVal) == ARM_AM::sub;
|
|
|
|
unsigned ShImm = ARM_AM::getAM2Offset(ShOpVal);
|
|
|
|
if (!isSub &&
|
|
|
|
(ShImm == 0 ||
|
|
|
|
((ShImm == 1 || ShImm == 2 || ShImm == 3) &&
|
|
|
|
ARM_AM::getAM2ShiftOpc(ShOpVal) == ARM_AM::lsl)))
|
|
|
|
return 3;
|
|
|
|
return 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
case ARM::LDRD: {
|
Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Partial reverts in:
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
X86FixupLEAs.cpp - Some functions return unsigned and arguably should be MCRegister
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
HexagonBitSimplify.cpp - Function takes BitTracker::RegisterRef which appears to be unsigned&
MachineVerifier.cpp - Ambiguous operator==() given MCRegister and const Register
PPCFastISel.cpp - No Register::operator-=()
PeepholeOptimizer.cpp - TargetInstrInfo::optimizeLoadInstr() takes an unsigned&
MachineTraceMetrics.cpp - MachineTraceMetrics lacks a suitable constructor
Manual fixups in:
ARMFastISel.cpp - ARMEmitLoad() now takes a Register& instead of unsigned&
HexagonSplitDouble.cpp - Ternary operator was ambiguous between unsigned/Register
HexagonConstExtenders.cpp - Has a local class named Register, used llvm::Register instead of Register.
PPCFastISel.cpp - PPCEmitLoad() now takes a Register& instead of unsigned&
Depends on D65919
Reviewers: arsenm, bogner, craig.topper, RKSimon
Reviewed By: arsenm
Subscribers: RKSimon, craig.topper, lenary, aemerson, wuzish, jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65962
llvm-svn: 369041
2019-08-15 19:22:08 +00:00
|
|
|
Register Rt = MI.getOperand(0).getReg();
|
|
|
|
Register Rn = MI.getOperand(2).getReg();
|
|
|
|
Register Rm = MI.getOperand(3).getReg();
|
2012-09-29 21:43:49 +00:00
|
|
|
if (Rm)
|
2016-06-30 00:01:54 +00:00
|
|
|
return (ARM_AM::getAM3Op(MI.getOperand(4).getImm()) == ARM_AM::sub) ? 4
|
|
|
|
: 3;
|
2012-09-29 21:43:49 +00:00
|
|
|
return (Rt == Rn) ? 3 : 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
case ARM::STRD: {
|
Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Partial reverts in:
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
X86FixupLEAs.cpp - Some functions return unsigned and arguably should be MCRegister
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
HexagonBitSimplify.cpp - Function takes BitTracker::RegisterRef which appears to be unsigned&
MachineVerifier.cpp - Ambiguous operator==() given MCRegister and const Register
PPCFastISel.cpp - No Register::operator-=()
PeepholeOptimizer.cpp - TargetInstrInfo::optimizeLoadInstr() takes an unsigned&
MachineTraceMetrics.cpp - MachineTraceMetrics lacks a suitable constructor
Manual fixups in:
ARMFastISel.cpp - ARMEmitLoad() now takes a Register& instead of unsigned&
HexagonSplitDouble.cpp - Ternary operator was ambiguous between unsigned/Register
HexagonConstExtenders.cpp - Has a local class named Register, used llvm::Register instead of Register.
PPCFastISel.cpp - PPCEmitLoad() now takes a Register& instead of unsigned&
Depends on D65919
Reviewers: arsenm, bogner, craig.topper, RKSimon
Reviewed By: arsenm
Subscribers: RKSimon, craig.topper, lenary, aemerson, wuzish, jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65962
llvm-svn: 369041
2019-08-15 19:22:08 +00:00
|
|
|
Register Rm = MI.getOperand(3).getReg();
|
2012-09-29 21:43:49 +00:00
|
|
|
if (Rm)
|
2016-06-30 00:01:54 +00:00
|
|
|
return (ARM_AM::getAM3Op(MI.getOperand(4).getImm()) == ARM_AM::sub) ? 4
|
|
|
|
: 3;
|
2012-09-29 21:43:49 +00:00
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
case ARM::LDRD_POST:
|
|
|
|
case ARM::t2LDRD_POST:
|
|
|
|
return 3;
|
|
|
|
|
|
|
|
case ARM::STRD_POST:
|
|
|
|
case ARM::t2STRD_POST:
|
|
|
|
return 4;
|
|
|
|
|
|
|
|
case ARM::LDRD_PRE: {
|
Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Partial reverts in:
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
X86FixupLEAs.cpp - Some functions return unsigned and arguably should be MCRegister
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
HexagonBitSimplify.cpp - Function takes BitTracker::RegisterRef which appears to be unsigned&
MachineVerifier.cpp - Ambiguous operator==() given MCRegister and const Register
PPCFastISel.cpp - No Register::operator-=()
PeepholeOptimizer.cpp - TargetInstrInfo::optimizeLoadInstr() takes an unsigned&
MachineTraceMetrics.cpp - MachineTraceMetrics lacks a suitable constructor
Manual fixups in:
ARMFastISel.cpp - ARMEmitLoad() now takes a Register& instead of unsigned&
HexagonSplitDouble.cpp - Ternary operator was ambiguous between unsigned/Register
HexagonConstExtenders.cpp - Has a local class named Register, used llvm::Register instead of Register.
PPCFastISel.cpp - PPCEmitLoad() now takes a Register& instead of unsigned&
Depends on D65919
Reviewers: arsenm, bogner, craig.topper, RKSimon
Reviewed By: arsenm
Subscribers: RKSimon, craig.topper, lenary, aemerson, wuzish, jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65962
llvm-svn: 369041
2019-08-15 19:22:08 +00:00
|
|
|
Register Rt = MI.getOperand(0).getReg();
|
|
|
|
Register Rn = MI.getOperand(3).getReg();
|
|
|
|
Register Rm = MI.getOperand(4).getReg();
|
2012-09-29 21:43:49 +00:00
|
|
|
if (Rm)
|
2016-06-30 00:01:54 +00:00
|
|
|
return (ARM_AM::getAM3Op(MI.getOperand(5).getImm()) == ARM_AM::sub) ? 5
|
|
|
|
: 4;
|
2012-09-29 21:43:49 +00:00
|
|
|
return (Rt == Rn) ? 4 : 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
case ARM::t2LDRD_PRE: {
|
Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Partial reverts in:
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
X86FixupLEAs.cpp - Some functions return unsigned and arguably should be MCRegister
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
HexagonBitSimplify.cpp - Function takes BitTracker::RegisterRef which appears to be unsigned&
MachineVerifier.cpp - Ambiguous operator==() given MCRegister and const Register
PPCFastISel.cpp - No Register::operator-=()
PeepholeOptimizer.cpp - TargetInstrInfo::optimizeLoadInstr() takes an unsigned&
MachineTraceMetrics.cpp - MachineTraceMetrics lacks a suitable constructor
Manual fixups in:
ARMFastISel.cpp - ARMEmitLoad() now takes a Register& instead of unsigned&
HexagonSplitDouble.cpp - Ternary operator was ambiguous between unsigned/Register
HexagonConstExtenders.cpp - Has a local class named Register, used llvm::Register instead of Register.
PPCFastISel.cpp - PPCEmitLoad() now takes a Register& instead of unsigned&
Depends on D65919
Reviewers: arsenm, bogner, craig.topper, RKSimon
Reviewed By: arsenm
Subscribers: RKSimon, craig.topper, lenary, aemerson, wuzish, jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65962
llvm-svn: 369041
2019-08-15 19:22:08 +00:00
|
|
|
Register Rt = MI.getOperand(0).getReg();
|
|
|
|
Register Rn = MI.getOperand(3).getReg();
|
2012-09-29 21:43:49 +00:00
|
|
|
return (Rt == Rn) ? 4 : 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
case ARM::STRD_PRE: {
|
Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Partial reverts in:
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
X86FixupLEAs.cpp - Some functions return unsigned and arguably should be MCRegister
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
HexagonBitSimplify.cpp - Function takes BitTracker::RegisterRef which appears to be unsigned&
MachineVerifier.cpp - Ambiguous operator==() given MCRegister and const Register
PPCFastISel.cpp - No Register::operator-=()
PeepholeOptimizer.cpp - TargetInstrInfo::optimizeLoadInstr() takes an unsigned&
MachineTraceMetrics.cpp - MachineTraceMetrics lacks a suitable constructor
Manual fixups in:
ARMFastISel.cpp - ARMEmitLoad() now takes a Register& instead of unsigned&
HexagonSplitDouble.cpp - Ternary operator was ambiguous between unsigned/Register
HexagonConstExtenders.cpp - Has a local class named Register, used llvm::Register instead of Register.
PPCFastISel.cpp - PPCEmitLoad() now takes a Register& instead of unsigned&
Depends on D65919
Reviewers: arsenm, bogner, craig.topper, RKSimon
Reviewed By: arsenm
Subscribers: RKSimon, craig.topper, lenary, aemerson, wuzish, jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65962
llvm-svn: 369041
2019-08-15 19:22:08 +00:00
|
|
|
Register Rm = MI.getOperand(4).getReg();
|
2012-09-29 21:43:49 +00:00
|
|
|
if (Rm)
|
2016-06-30 00:01:54 +00:00
|
|
|
return (ARM_AM::getAM3Op(MI.getOperand(5).getImm()) == ARM_AM::sub) ? 5
|
|
|
|
: 4;
|
2012-09-29 21:43:49 +00:00
|
|
|
return 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
case ARM::t2STRD_PRE:
|
|
|
|
return 3;
|
|
|
|
|
|
|
|
case ARM::t2LDR_POST:
|
|
|
|
case ARM::t2LDRB_POST:
|
|
|
|
case ARM::t2LDRB_PRE:
|
|
|
|
case ARM::t2LDRSBi12:
|
|
|
|
case ARM::t2LDRSBi8:
|
|
|
|
case ARM::t2LDRSBpci:
|
|
|
|
case ARM::t2LDRSBs:
|
|
|
|
case ARM::t2LDRH_POST:
|
|
|
|
case ARM::t2LDRH_PRE:
|
|
|
|
case ARM::t2LDRSBT:
|
|
|
|
case ARM::t2LDRSB_POST:
|
|
|
|
case ARM::t2LDRSB_PRE:
|
|
|
|
case ARM::t2LDRSH_POST:
|
|
|
|
case ARM::t2LDRSH_PRE:
|
|
|
|
case ARM::t2LDRSHi12:
|
|
|
|
case ARM::t2LDRSHi8:
|
|
|
|
case ARM::t2LDRSHpci:
|
|
|
|
case ARM::t2LDRSHs:
|
|
|
|
return 2;
|
|
|
|
|
|
|
|
case ARM::t2LDRDi8: {
|
Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Partial reverts in:
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
X86FixupLEAs.cpp - Some functions return unsigned and arguably should be MCRegister
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
HexagonBitSimplify.cpp - Function takes BitTracker::RegisterRef which appears to be unsigned&
MachineVerifier.cpp - Ambiguous operator==() given MCRegister and const Register
PPCFastISel.cpp - No Register::operator-=()
PeepholeOptimizer.cpp - TargetInstrInfo::optimizeLoadInstr() takes an unsigned&
MachineTraceMetrics.cpp - MachineTraceMetrics lacks a suitable constructor
Manual fixups in:
ARMFastISel.cpp - ARMEmitLoad() now takes a Register& instead of unsigned&
HexagonSplitDouble.cpp - Ternary operator was ambiguous between unsigned/Register
HexagonConstExtenders.cpp - Has a local class named Register, used llvm::Register instead of Register.
PPCFastISel.cpp - PPCEmitLoad() now takes a Register& instead of unsigned&
Depends on D65919
Reviewers: arsenm, bogner, craig.topper, RKSimon
Reviewed By: arsenm
Subscribers: RKSimon, craig.topper, lenary, aemerson, wuzish, jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65962
llvm-svn: 369041
2019-08-15 19:22:08 +00:00
|
|
|
Register Rt = MI.getOperand(0).getReg();
|
|
|
|
Register Rn = MI.getOperand(2).getReg();
|
2012-09-29 21:43:49 +00:00
|
|
|
return (Rt == Rn) ? 3 : 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
case ARM::t2STRB_POST:
|
|
|
|
case ARM::t2STRB_PRE:
|
|
|
|
case ARM::t2STRBs:
|
|
|
|
case ARM::t2STRDi8:
|
|
|
|
case ARM::t2STRH_POST:
|
|
|
|
case ARM::t2STRH_PRE:
|
|
|
|
case ARM::t2STRHs:
|
|
|
|
case ARM::t2STR_POST:
|
|
|
|
case ARM::t2STR_PRE:
|
|
|
|
case ARM::t2STRs:
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-14 18:48:46 +00:00
|
|
|
// Return the number of 32-bit words loaded by LDM or stored by STM. If this
|
|
|
|
// can't be easily determined return 0 (missing MachineMemOperand).
|
|
|
|
//
|
|
|
|
// FIXME: The current MachineInstr design does not support relying on machine
|
|
|
|
// mem operands to determine the width of a memory access. Instead, we expect
|
|
|
|
// the target to provide this information based on the instruction opcode and
|
2014-08-29 21:53:01 +00:00
|
|
|
// operands. However, using MachineMemOperand is the best solution now for
|
2012-09-14 18:48:46 +00:00
|
|
|
// two reasons:
|
|
|
|
//
|
|
|
|
// 1) getNumMicroOps tries to infer LDM memory width from the total number of MI
|
|
|
|
// operands. This is much more dangerous than using the MachineMemOperand
|
|
|
|
// sizes because CodeGen passes can insert/remove optional machine operands. In
|
|
|
|
// fact, it's totally incorrect for preRA passes and appears to be wrong for
|
|
|
|
// postRA passes as well.
|
|
|
|
//
|
|
|
|
// 2) getNumLDMAddresses is only used by the scheduling machine model and any
|
|
|
|
// machine model that calls this should handle the unknown (zero size) case.
|
|
|
|
//
|
|
|
|
// Long term, we should require a target hook that verifies MachineMemOperand
|
|
|
|
// sizes during MC lowering. That target hook should be local to MC lowering
|
|
|
|
// because we can't ensure that it is aware of other MI forms. Doing this will
|
|
|
|
// ensure that MachineMemOperands are correctly propagated through all passes.
|
2016-06-30 00:01:54 +00:00
|
|
|
unsigned ARMBaseInstrInfo::getNumLDMAddresses(const MachineInstr &MI) const {
|
2012-09-14 18:48:46 +00:00
|
|
|
unsigned Size = 0;
|
2016-06-30 00:01:54 +00:00
|
|
|
for (MachineInstr::mmo_iterator I = MI.memoperands_begin(),
|
|
|
|
E = MI.memoperands_end();
|
|
|
|
I != E; ++I) {
|
2012-09-14 18:48:46 +00:00
|
|
|
Size += (*I)->getSize();
|
|
|
|
}
|
2019-03-27 18:33:30 +00:00
|
|
|
// FIXME: The scheduler currently can't handle values larger than 16. But
|
|
|
|
// the values can actually go up to 32 for floating-point load/store
|
|
|
|
// multiple (VLDMIA etc.). Also, the way this code is reasoning about memory
|
|
|
|
// operations isn't right; we could end up with "extra" memory operands for
|
|
|
|
// various reasons, like tail merge merging two memory operations.
|
|
|
|
return std::min(Size / 4, 16U);
|
2012-09-14 18:48:46 +00:00
|
|
|
}
|
|
|
|
|
2016-06-27 09:08:23 +00:00
|
|
|
static unsigned getNumMicroOpsSingleIssuePlusExtras(unsigned Opc,
|
|
|
|
unsigned NumRegs) {
|
|
|
|
unsigned UOps = 1 + NumRegs; // 1 for address computation.
|
|
|
|
switch (Opc) {
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
case ARM::VLDMDIA_UPD:
|
|
|
|
case ARM::VLDMDDB_UPD:
|
|
|
|
case ARM::VLDMSIA_UPD:
|
|
|
|
case ARM::VLDMSDB_UPD:
|
|
|
|
case ARM::VSTMDIA_UPD:
|
|
|
|
case ARM::VSTMDDB_UPD:
|
|
|
|
case ARM::VSTMSIA_UPD:
|
|
|
|
case ARM::VSTMSDB_UPD:
|
|
|
|
case ARM::LDMIA_UPD:
|
|
|
|
case ARM::LDMDA_UPD:
|
|
|
|
case ARM::LDMDB_UPD:
|
|
|
|
case ARM::LDMIB_UPD:
|
|
|
|
case ARM::STMIA_UPD:
|
|
|
|
case ARM::STMDA_UPD:
|
|
|
|
case ARM::STMDB_UPD:
|
|
|
|
case ARM::STMIB_UPD:
|
|
|
|
case ARM::tLDMIA_UPD:
|
|
|
|
case ARM::tSTMIA_UPD:
|
|
|
|
case ARM::t2LDMIA_UPD:
|
|
|
|
case ARM::t2LDMDB_UPD:
|
|
|
|
case ARM::t2STMIA_UPD:
|
|
|
|
case ARM::t2STMDB_UPD:
|
|
|
|
++UOps; // One for base register writeback.
|
|
|
|
break;
|
|
|
|
case ARM::LDMIA_RET:
|
|
|
|
case ARM::tPOP_RET:
|
|
|
|
case ARM::t2LDMIA_RET:
|
|
|
|
UOps += 2; // One for base reg wb, one for write to pc.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return UOps;
|
|
|
|
}
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
unsigned ARMBaseInstrInfo::getNumMicroOps(const InstrItineraryData *ItinData,
|
|
|
|
const MachineInstr &MI) const {
|
2010-09-10 01:29:16 +00:00
|
|
|
if (!ItinData || ItinData->isEmpty())
|
2010-09-09 18:18:55 +00:00
|
|
|
return 1;
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
const MCInstrDesc &Desc = MI.getDesc();
|
2010-09-09 18:18:55 +00:00
|
|
|
unsigned Class = Desc.getSchedClass();
|
2012-07-02 18:10:42 +00:00
|
|
|
int ItinUOps = ItinData->getNumMicroOps(Class);
|
2012-09-29 21:43:49 +00:00
|
|
|
if (ItinUOps >= 0) {
|
|
|
|
if (Subtarget.isSwift() && (Desc.mayLoad() || Desc.mayStore()))
|
|
|
|
return getNumMicroOpsSwiftLdSt(ItinData, MI);
|
|
|
|
|
2012-07-02 18:10:42 +00:00
|
|
|
return ItinUOps;
|
2012-09-29 21:43:49 +00:00
|
|
|
}
|
2010-09-09 18:18:55 +00:00
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
unsigned Opc = MI.getOpcode();
|
2010-09-09 18:18:55 +00:00
|
|
|
switch (Opc) {
|
|
|
|
default:
|
|
|
|
llvm_unreachable("Unexpected multi-uops instruction!");
|
2010-11-16 01:16:36 +00:00
|
|
|
case ARM::VLDMQIA:
|
|
|
|
case ARM::VSTMQIA:
|
2010-09-09 18:18:55 +00:00
|
|
|
return 2;
|
|
|
|
|
|
|
|
// The number of uOps for load / store multiple are determined by the number
|
|
|
|
// registers.
|
2010-12-24 04:28:06 +00:00
|
|
|
//
|
2010-09-10 01:29:16 +00:00
|
|
|
// On Cortex-A8, each pair of register loads / stores can be scheduled on the
|
|
|
|
// same cycle. The scheduling for the first load / store must be done
|
2012-07-23 08:51:15 +00:00
|
|
|
// separately by assuming the address is not 64-bit aligned.
|
2010-11-16 01:16:36 +00:00
|
|
|
//
|
2010-09-10 01:29:16 +00:00
|
|
|
// On Cortex-A9, the formula is simply (#reg / 2) + (#reg % 2). If the address
|
2010-11-16 01:16:36 +00:00
|
|
|
// is not 64-bit aligned, then AGU would take an extra cycle. For VFP / NEON
|
|
|
|
// load / store multiple, the formula is (#reg / 2) + (#reg % 2) + 1.
|
|
|
|
case ARM::VLDMDIA:
|
|
|
|
case ARM::VLDMDIA_UPD:
|
|
|
|
case ARM::VLDMDDB_UPD:
|
|
|
|
case ARM::VLDMSIA:
|
|
|
|
case ARM::VLDMSIA_UPD:
|
|
|
|
case ARM::VLDMSDB_UPD:
|
|
|
|
case ARM::VSTMDIA:
|
|
|
|
case ARM::VSTMDIA_UPD:
|
|
|
|
case ARM::VSTMDDB_UPD:
|
|
|
|
case ARM::VSTMSIA:
|
|
|
|
case ARM::VSTMSIA_UPD:
|
|
|
|
case ARM::VSTMSDB_UPD: {
|
2016-06-30 00:01:54 +00:00
|
|
|
unsigned NumRegs = MI.getNumOperands() - Desc.getNumOperands();
|
2010-09-09 18:18:55 +00:00
|
|
|
return (NumRegs / 2) + (NumRegs % 2) + 1;
|
|
|
|
}
|
2010-11-16 01:16:36 +00:00
|
|
|
|
|
|
|
case ARM::LDMIA_RET:
|
|
|
|
case ARM::LDMIA:
|
|
|
|
case ARM::LDMDA:
|
|
|
|
case ARM::LDMDB:
|
|
|
|
case ARM::LDMIB:
|
|
|
|
case ARM::LDMIA_UPD:
|
|
|
|
case ARM::LDMDA_UPD:
|
|
|
|
case ARM::LDMDB_UPD:
|
|
|
|
case ARM::LDMIB_UPD:
|
|
|
|
case ARM::STMIA:
|
|
|
|
case ARM::STMDA:
|
|
|
|
case ARM::STMDB:
|
|
|
|
case ARM::STMIB:
|
|
|
|
case ARM::STMIA_UPD:
|
|
|
|
case ARM::STMDA_UPD:
|
|
|
|
case ARM::STMDB_UPD:
|
|
|
|
case ARM::STMIB_UPD:
|
|
|
|
case ARM::tLDMIA:
|
|
|
|
case ARM::tLDMIA_UPD:
|
|
|
|
case ARM::tSTMIA_UPD:
|
2010-09-09 18:18:55 +00:00
|
|
|
case ARM::tPOP_RET:
|
|
|
|
case ARM::tPOP:
|
|
|
|
case ARM::tPUSH:
|
2010-11-16 01:16:36 +00:00
|
|
|
case ARM::t2LDMIA_RET:
|
|
|
|
case ARM::t2LDMIA:
|
|
|
|
case ARM::t2LDMDB:
|
|
|
|
case ARM::t2LDMIA_UPD:
|
|
|
|
case ARM::t2LDMDB_UPD:
|
|
|
|
case ARM::t2STMIA:
|
|
|
|
case ARM::t2STMDB:
|
|
|
|
case ARM::t2STMIA_UPD:
|
|
|
|
case ARM::t2STMDB_UPD: {
|
2016-06-30 00:01:54 +00:00
|
|
|
unsigned NumRegs = MI.getNumOperands() - Desc.getNumOperands() + 1;
|
2016-06-27 09:08:23 +00:00
|
|
|
switch (Subtarget.getLdStMultipleTiming()) {
|
|
|
|
case ARMSubtarget::SingleIssuePlusExtras:
|
|
|
|
return getNumMicroOpsSingleIssuePlusExtras(Opc, NumRegs);
|
|
|
|
case ARMSubtarget::SingleIssue:
|
|
|
|
// Assume the worst.
|
|
|
|
return NumRegs;
|
|
|
|
case ARMSubtarget::DoubleIssue: {
|
2010-11-03 00:45:17 +00:00
|
|
|
if (NumRegs < 4)
|
|
|
|
return 2;
|
|
|
|
// 4 registers would be issued: 2, 2.
|
|
|
|
// 5 registers would be issued: 2, 2, 1.
|
2016-06-27 09:08:23 +00:00
|
|
|
unsigned UOps = (NumRegs / 2);
|
2010-11-03 00:45:17 +00:00
|
|
|
if (NumRegs % 2)
|
2016-06-27 09:08:23 +00:00
|
|
|
++UOps;
|
|
|
|
return UOps;
|
|
|
|
}
|
|
|
|
case ARMSubtarget::DoubleIssueCheckUnalignedAccess: {
|
|
|
|
unsigned UOps = (NumRegs / 2);
|
2010-09-10 01:29:16 +00:00
|
|
|
// If there are odd number of registers or if it's not 64-bit aligned,
|
|
|
|
// then it takes an extra AGU (Address Generation Unit) cycle.
|
2016-06-30 00:01:54 +00:00
|
|
|
if ((NumRegs % 2) || !MI.hasOneMemOperand() ||
|
[Alignment][NFC] MachineMemOperand::getAlign/getBaseAlign
Summary:
This is patch is part of a series to introduce an Alignment type.
See this thread for context: http://lists.llvm.org/pipermail/llvm-dev/2019-July/133851.html
See this patch for the introduction of the type: https://reviews.llvm.org/D64790
Reviewers: courbet
Subscribers: arsenm, dschuff, sdardis, nemanjai, jvesely, nhaehnle, sbc100, jgravelle-google, hiraditya, aheejin, kbarton, jrtc27, atanasyan, jfb, kerbowa, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D76925
2020-03-27 13:51:59 +00:00
|
|
|
(*MI.memoperands_begin())->getAlign() < Align(8))
|
2016-06-27 09:08:23 +00:00
|
|
|
++UOps;
|
|
|
|
return UOps;
|
|
|
|
}
|
2010-10-05 06:00:33 +00:00
|
|
|
}
|
2010-09-09 18:18:55 +00:00
|
|
|
}
|
|
|
|
}
|
2016-06-27 09:08:23 +00:00
|
|
|
llvm_unreachable("Didn't find the number of microops");
|
2010-09-09 18:18:55 +00:00
|
|
|
}
|
2010-10-06 06:27:31 +00:00
|
|
|
|
2010-10-07 23:12:15 +00:00
|
|
|
int
|
|
|
|
ARMBaseInstrInfo::getVLDMDefCycle(const InstrItineraryData *ItinData,
|
2011-06-28 19:10:37 +00:00
|
|
|
const MCInstrDesc &DefMCID,
|
2010-10-07 23:12:15 +00:00
|
|
|
unsigned DefClass,
|
|
|
|
unsigned DefIdx, unsigned DefAlign) const {
|
2011-06-28 19:10:37 +00:00
|
|
|
int RegNo = (int)(DefIdx+1) - DefMCID.getNumOperands() + 1;
|
2010-10-07 23:12:15 +00:00
|
|
|
if (RegNo <= 0)
|
|
|
|
// Def is the address writeback.
|
|
|
|
return ItinData->getOperandCycle(DefClass, DefIdx);
|
|
|
|
|
|
|
|
int DefCycle;
|
2014-04-01 14:10:07 +00:00
|
|
|
if (Subtarget.isCortexA8() || Subtarget.isCortexA7()) {
|
2010-10-07 23:12:15 +00:00
|
|
|
// (regno / 2) + (regno % 2) + 1
|
|
|
|
DefCycle = RegNo / 2 + 1;
|
|
|
|
if (RegNo % 2)
|
|
|
|
++DefCycle;
|
2012-09-29 21:43:49 +00:00
|
|
|
} else if (Subtarget.isLikeA9() || Subtarget.isSwift()) {
|
2010-10-07 23:12:15 +00:00
|
|
|
DefCycle = RegNo;
|
|
|
|
bool isSLoad = false;
|
2010-11-16 01:16:36 +00:00
|
|
|
|
2011-06-28 19:10:37 +00:00
|
|
|
switch (DefMCID.getOpcode()) {
|
2010-10-07 23:12:15 +00:00
|
|
|
default: break;
|
2010-11-16 01:16:36 +00:00
|
|
|
case ARM::VLDMSIA:
|
|
|
|
case ARM::VLDMSIA_UPD:
|
|
|
|
case ARM::VLDMSDB_UPD:
|
2010-10-07 23:12:15 +00:00
|
|
|
isSLoad = true;
|
|
|
|
break;
|
|
|
|
}
|
2010-11-16 01:16:36 +00:00
|
|
|
|
2010-10-07 23:12:15 +00:00
|
|
|
// If there are odd number of 'S' registers or if it's not 64-bit aligned,
|
|
|
|
// then it takes an extra cycle.
|
|
|
|
if ((isSLoad && (RegNo % 2)) || DefAlign < 8)
|
|
|
|
++DefCycle;
|
|
|
|
} else {
|
|
|
|
// Assume the worst.
|
|
|
|
DefCycle = RegNo + 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
return DefCycle;
|
|
|
|
}
|
|
|
|
|
2017-06-02 08:53:19 +00:00
|
|
|
bool ARMBaseInstrInfo::isLDMBaseRegInList(const MachineInstr &MI) const {
|
Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Partial reverts in:
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
X86FixupLEAs.cpp - Some functions return unsigned and arguably should be MCRegister
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
HexagonBitSimplify.cpp - Function takes BitTracker::RegisterRef which appears to be unsigned&
MachineVerifier.cpp - Ambiguous operator==() given MCRegister and const Register
PPCFastISel.cpp - No Register::operator-=()
PeepholeOptimizer.cpp - TargetInstrInfo::optimizeLoadInstr() takes an unsigned&
MachineTraceMetrics.cpp - MachineTraceMetrics lacks a suitable constructor
Manual fixups in:
ARMFastISel.cpp - ARMEmitLoad() now takes a Register& instead of unsigned&
HexagonSplitDouble.cpp - Ternary operator was ambiguous between unsigned/Register
HexagonConstExtenders.cpp - Has a local class named Register, used llvm::Register instead of Register.
PPCFastISel.cpp - PPCEmitLoad() now takes a Register& instead of unsigned&
Depends on D65919
Reviewers: arsenm, bogner, craig.topper, RKSimon
Reviewed By: arsenm
Subscribers: RKSimon, craig.topper, lenary, aemerson, wuzish, jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65962
llvm-svn: 369041
2019-08-15 19:22:08 +00:00
|
|
|
Register BaseReg = MI.getOperand(0).getReg();
|
2017-06-02 08:53:19 +00:00
|
|
|
for (unsigned i = 1, sz = MI.getNumOperands(); i < sz; ++i) {
|
|
|
|
const auto &Op = MI.getOperand(i);
|
|
|
|
if (Op.isReg() && Op.getReg() == BaseReg)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
unsigned
|
|
|
|
ARMBaseInstrInfo::getLDMVariableDefsSize(const MachineInstr &MI) const {
|
2018-01-09 17:31:07 +00:00
|
|
|
// ins GPR:$Rn, $p (2xOp), reglist:$regs, variable_ops
|
|
|
|
// (outs GPR:$wb), (ins GPR:$Rn, $p (2xOp), reglist:$regs, variable_ops)
|
2017-06-02 08:53:19 +00:00
|
|
|
return MI.getNumOperands() + 1 - MI.getDesc().getNumOperands();
|
|
|
|
}
|
|
|
|
|
2010-10-07 23:12:15 +00:00
|
|
|
int
|
|
|
|
ARMBaseInstrInfo::getLDMDefCycle(const InstrItineraryData *ItinData,
|
2011-06-28 19:10:37 +00:00
|
|
|
const MCInstrDesc &DefMCID,
|
2010-10-07 23:12:15 +00:00
|
|
|
unsigned DefClass,
|
|
|
|
unsigned DefIdx, unsigned DefAlign) const {
|
2011-06-28 19:10:37 +00:00
|
|
|
int RegNo = (int)(DefIdx+1) - DefMCID.getNumOperands() + 1;
|
2010-10-07 23:12:15 +00:00
|
|
|
if (RegNo <= 0)
|
|
|
|
// Def is the address writeback.
|
|
|
|
return ItinData->getOperandCycle(DefClass, DefIdx);
|
|
|
|
|
|
|
|
int DefCycle;
|
2014-04-01 14:10:07 +00:00
|
|
|
if (Subtarget.isCortexA8() || Subtarget.isCortexA7()) {
|
2010-10-07 23:12:15 +00:00
|
|
|
// 4 registers would be issued: 1, 2, 1.
|
|
|
|
// 5 registers would be issued: 1, 2, 2.
|
|
|
|
DefCycle = RegNo / 2;
|
|
|
|
if (DefCycle < 1)
|
|
|
|
DefCycle = 1;
|
|
|
|
// Result latency is issue cycle + 2: E2.
|
|
|
|
DefCycle += 2;
|
2012-09-29 21:43:49 +00:00
|
|
|
} else if (Subtarget.isLikeA9() || Subtarget.isSwift()) {
|
2010-10-07 23:12:15 +00:00
|
|
|
DefCycle = (RegNo / 2);
|
|
|
|
// If there are odd number of registers or if it's not 64-bit aligned,
|
|
|
|
// then it takes an extra AGU (Address Generation Unit) cycle.
|
|
|
|
if ((RegNo % 2) || DefAlign < 8)
|
|
|
|
++DefCycle;
|
|
|
|
// Result latency is AGU cycles + 2.
|
|
|
|
DefCycle += 2;
|
|
|
|
} else {
|
|
|
|
// Assume the worst.
|
|
|
|
DefCycle = RegNo + 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
return DefCycle;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
ARMBaseInstrInfo::getVSTMUseCycle(const InstrItineraryData *ItinData,
|
2011-06-28 19:10:37 +00:00
|
|
|
const MCInstrDesc &UseMCID,
|
2010-10-07 23:12:15 +00:00
|
|
|
unsigned UseClass,
|
|
|
|
unsigned UseIdx, unsigned UseAlign) const {
|
2011-06-28 19:10:37 +00:00
|
|
|
int RegNo = (int)(UseIdx+1) - UseMCID.getNumOperands() + 1;
|
2010-10-07 23:12:15 +00:00
|
|
|
if (RegNo <= 0)
|
|
|
|
return ItinData->getOperandCycle(UseClass, UseIdx);
|
|
|
|
|
|
|
|
int UseCycle;
|
2014-04-01 14:10:07 +00:00
|
|
|
if (Subtarget.isCortexA8() || Subtarget.isCortexA7()) {
|
2010-10-07 23:12:15 +00:00
|
|
|
// (regno / 2) + (regno % 2) + 1
|
|
|
|
UseCycle = RegNo / 2 + 1;
|
|
|
|
if (RegNo % 2)
|
|
|
|
++UseCycle;
|
2012-09-29 21:43:49 +00:00
|
|
|
} else if (Subtarget.isLikeA9() || Subtarget.isSwift()) {
|
2010-10-07 23:12:15 +00:00
|
|
|
UseCycle = RegNo;
|
|
|
|
bool isSStore = false;
|
2010-11-16 01:16:36 +00:00
|
|
|
|
2011-06-28 19:10:37 +00:00
|
|
|
switch (UseMCID.getOpcode()) {
|
2010-10-07 23:12:15 +00:00
|
|
|
default: break;
|
2010-11-16 01:16:36 +00:00
|
|
|
case ARM::VSTMSIA:
|
|
|
|
case ARM::VSTMSIA_UPD:
|
|
|
|
case ARM::VSTMSDB_UPD:
|
2010-10-07 23:12:15 +00:00
|
|
|
isSStore = true;
|
|
|
|
break;
|
|
|
|
}
|
2010-11-16 01:16:36 +00:00
|
|
|
|
2010-10-07 23:12:15 +00:00
|
|
|
// If there are odd number of 'S' registers or if it's not 64-bit aligned,
|
|
|
|
// then it takes an extra cycle.
|
|
|
|
if ((isSStore && (RegNo % 2)) || UseAlign < 8)
|
|
|
|
++UseCycle;
|
|
|
|
} else {
|
|
|
|
// Assume the worst.
|
|
|
|
UseCycle = RegNo + 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
return UseCycle;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
ARMBaseInstrInfo::getSTMUseCycle(const InstrItineraryData *ItinData,
|
2011-06-28 19:10:37 +00:00
|
|
|
const MCInstrDesc &UseMCID,
|
2010-10-07 23:12:15 +00:00
|
|
|
unsigned UseClass,
|
|
|
|
unsigned UseIdx, unsigned UseAlign) const {
|
2011-06-28 19:10:37 +00:00
|
|
|
int RegNo = (int)(UseIdx+1) - UseMCID.getNumOperands() + 1;
|
2010-10-07 23:12:15 +00:00
|
|
|
if (RegNo <= 0)
|
|
|
|
return ItinData->getOperandCycle(UseClass, UseIdx);
|
|
|
|
|
|
|
|
int UseCycle;
|
2014-04-01 14:10:07 +00:00
|
|
|
if (Subtarget.isCortexA8() || Subtarget.isCortexA7()) {
|
2010-10-07 23:12:15 +00:00
|
|
|
UseCycle = RegNo / 2;
|
|
|
|
if (UseCycle < 2)
|
|
|
|
UseCycle = 2;
|
|
|
|
// Read in E3.
|
|
|
|
UseCycle += 2;
|
2012-09-29 21:43:49 +00:00
|
|
|
} else if (Subtarget.isLikeA9() || Subtarget.isSwift()) {
|
2010-10-07 23:12:15 +00:00
|
|
|
UseCycle = (RegNo / 2);
|
|
|
|
// If there are odd number of registers or if it's not 64-bit aligned,
|
|
|
|
// then it takes an extra AGU (Address Generation Unit) cycle.
|
|
|
|
if ((RegNo % 2) || UseAlign < 8)
|
|
|
|
++UseCycle;
|
|
|
|
} else {
|
|
|
|
// Assume the worst.
|
|
|
|
UseCycle = 1;
|
|
|
|
}
|
|
|
|
return UseCycle;
|
|
|
|
}
|
|
|
|
|
2010-10-06 06:27:31 +00:00
|
|
|
int
|
|
|
|
ARMBaseInstrInfo::getOperandLatency(const InstrItineraryData *ItinData,
|
2011-06-28 19:10:37 +00:00
|
|
|
const MCInstrDesc &DefMCID,
|
2010-10-06 06:27:31 +00:00
|
|
|
unsigned DefIdx, unsigned DefAlign,
|
2011-06-28 19:10:37 +00:00
|
|
|
const MCInstrDesc &UseMCID,
|
2010-10-06 06:27:31 +00:00
|
|
|
unsigned UseIdx, unsigned UseAlign) const {
|
2011-06-28 19:10:37 +00:00
|
|
|
unsigned DefClass = DefMCID.getSchedClass();
|
|
|
|
unsigned UseClass = UseMCID.getSchedClass();
|
2010-10-06 06:27:31 +00:00
|
|
|
|
2011-06-28 19:10:37 +00:00
|
|
|
if (DefIdx < DefMCID.getNumDefs() && UseIdx < UseMCID.getNumOperands())
|
2010-10-06 06:27:31 +00:00
|
|
|
return ItinData->getOperandLatency(DefClass, DefIdx, UseClass, UseIdx);
|
|
|
|
|
|
|
|
// This may be a def / use of a variable_ops instruction, the operand
|
|
|
|
// latency might be determinable dynamically. Let the target try to
|
|
|
|
// figure it out.
|
2010-10-28 02:00:25 +00:00
|
|
|
int DefCycle = -1;
|
2010-10-28 06:47:08 +00:00
|
|
|
bool LdmBypass = false;
|
2011-06-28 19:10:37 +00:00
|
|
|
switch (DefMCID.getOpcode()) {
|
2010-10-06 06:27:31 +00:00
|
|
|
default:
|
|
|
|
DefCycle = ItinData->getOperandCycle(DefClass, DefIdx);
|
|
|
|
break;
|
2010-11-16 01:16:36 +00:00
|
|
|
|
|
|
|
case ARM::VLDMDIA:
|
|
|
|
case ARM::VLDMDIA_UPD:
|
|
|
|
case ARM::VLDMDDB_UPD:
|
|
|
|
case ARM::VLDMSIA:
|
|
|
|
case ARM::VLDMSIA_UPD:
|
|
|
|
case ARM::VLDMSDB_UPD:
|
2011-06-28 19:10:37 +00:00
|
|
|
DefCycle = getVLDMDefCycle(ItinData, DefMCID, DefClass, DefIdx, DefAlign);
|
2010-10-07 01:50:48 +00:00
|
|
|
break;
|
2010-11-16 01:16:36 +00:00
|
|
|
|
|
|
|
case ARM::LDMIA_RET:
|
|
|
|
case ARM::LDMIA:
|
|
|
|
case ARM::LDMDA:
|
|
|
|
case ARM::LDMDB:
|
|
|
|
case ARM::LDMIB:
|
|
|
|
case ARM::LDMIA_UPD:
|
|
|
|
case ARM::LDMDA_UPD:
|
|
|
|
case ARM::LDMDB_UPD:
|
|
|
|
case ARM::LDMIB_UPD:
|
|
|
|
case ARM::tLDMIA:
|
|
|
|
case ARM::tLDMIA_UPD:
|
2010-10-06 06:27:31 +00:00
|
|
|
case ARM::tPUSH:
|
2010-11-16 01:16:36 +00:00
|
|
|
case ARM::t2LDMIA_RET:
|
|
|
|
case ARM::t2LDMIA:
|
|
|
|
case ARM::t2LDMDB:
|
|
|
|
case ARM::t2LDMIA_UPD:
|
|
|
|
case ARM::t2LDMDB_UPD:
|
2017-01-26 23:40:06 +00:00
|
|
|
LdmBypass = true;
|
2011-06-28 19:10:37 +00:00
|
|
|
DefCycle = getLDMDefCycle(ItinData, DefMCID, DefClass, DefIdx, DefAlign);
|
2010-10-07 23:12:15 +00:00
|
|
|
break;
|
2010-10-06 06:27:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (DefCycle == -1)
|
|
|
|
// We can't seem to determine the result latency of the def, assume it's 2.
|
|
|
|
DefCycle = 2;
|
|
|
|
|
|
|
|
int UseCycle = -1;
|
2011-06-28 19:10:37 +00:00
|
|
|
switch (UseMCID.getOpcode()) {
|
2010-10-06 06:27:31 +00:00
|
|
|
default:
|
|
|
|
UseCycle = ItinData->getOperandCycle(UseClass, UseIdx);
|
|
|
|
break;
|
2010-11-16 01:16:36 +00:00
|
|
|
|
|
|
|
case ARM::VSTMDIA:
|
|
|
|
case ARM::VSTMDIA_UPD:
|
|
|
|
case ARM::VSTMDDB_UPD:
|
|
|
|
case ARM::VSTMSIA:
|
|
|
|
case ARM::VSTMSIA_UPD:
|
|
|
|
case ARM::VSTMSDB_UPD:
|
2011-06-28 19:10:37 +00:00
|
|
|
UseCycle = getVSTMUseCycle(ItinData, UseMCID, UseClass, UseIdx, UseAlign);
|
2010-10-07 01:50:48 +00:00
|
|
|
break;
|
2010-11-16 01:16:36 +00:00
|
|
|
|
|
|
|
case ARM::STMIA:
|
|
|
|
case ARM::STMDA:
|
|
|
|
case ARM::STMDB:
|
|
|
|
case ARM::STMIB:
|
|
|
|
case ARM::STMIA_UPD:
|
|
|
|
case ARM::STMDA_UPD:
|
|
|
|
case ARM::STMDB_UPD:
|
|
|
|
case ARM::STMIB_UPD:
|
|
|
|
case ARM::tSTMIA_UPD:
|
2010-10-06 06:27:31 +00:00
|
|
|
case ARM::tPOP_RET:
|
|
|
|
case ARM::tPOP:
|
2010-11-16 01:16:36 +00:00
|
|
|
case ARM::t2STMIA:
|
|
|
|
case ARM::t2STMDB:
|
|
|
|
case ARM::t2STMIA_UPD:
|
|
|
|
case ARM::t2STMDB_UPD:
|
2011-06-28 19:10:37 +00:00
|
|
|
UseCycle = getSTMUseCycle(ItinData, UseMCID, UseClass, UseIdx, UseAlign);
|
2010-10-07 01:50:48 +00:00
|
|
|
break;
|
2010-10-06 06:27:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (UseCycle == -1)
|
|
|
|
// Assume it's read in the first stage.
|
|
|
|
UseCycle = 1;
|
|
|
|
|
|
|
|
UseCycle = DefCycle - UseCycle + 1;
|
|
|
|
if (UseCycle > 0) {
|
|
|
|
if (LdmBypass) {
|
|
|
|
// It's a variable_ops instruction so we can't use DefIdx here. Just use
|
|
|
|
// first def operand.
|
2011-06-28 19:10:37 +00:00
|
|
|
if (ItinData->hasPipelineForwarding(DefClass, DefMCID.getNumOperands()-1,
|
2010-10-06 06:27:31 +00:00
|
|
|
UseClass, UseIdx))
|
|
|
|
--UseCycle;
|
|
|
|
} else if (ItinData->hasPipelineForwarding(DefClass, DefIdx,
|
2010-11-16 01:16:36 +00:00
|
|
|
UseClass, UseIdx)) {
|
2010-10-06 06:27:31 +00:00
|
|
|
--UseCycle;
|
2010-11-16 01:16:36 +00:00
|
|
|
}
|
2010-10-06 06:27:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return UseCycle;
|
|
|
|
}
|
|
|
|
|
2011-12-14 02:11:42 +00:00
|
|
|
static const MachineInstr *getBundledDefMI(const TargetRegisterInfo *TRI,
|
2011-12-14 20:00:08 +00:00
|
|
|
const MachineInstr *MI, unsigned Reg,
|
2011-12-14 02:11:42 +00:00
|
|
|
unsigned &DefIdx, unsigned &Dist) {
|
|
|
|
Dist = 0;
|
|
|
|
|
|
|
|
MachineBasicBlock::const_iterator I = MI; ++I;
|
2016-02-22 21:30:15 +00:00
|
|
|
MachineBasicBlock::const_instr_iterator II = std::prev(I.getInstrIterator());
|
2011-12-14 02:11:42 +00:00
|
|
|
assert(II->isInsideBundle() && "Empty bundle?");
|
|
|
|
|
|
|
|
int Idx = -1;
|
|
|
|
while (II->isInsideBundle()) {
|
|
|
|
Idx = II->findRegisterDefOperandIdx(Reg, false, true, TRI);
|
|
|
|
if (Idx != -1)
|
|
|
|
break;
|
|
|
|
--II;
|
|
|
|
++Dist;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(Idx != -1 && "Cannot find bundled definition!");
|
|
|
|
DefIdx = Idx;
|
2015-10-19 23:25:57 +00:00
|
|
|
return &*II;
|
2011-12-14 02:11:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static const MachineInstr *getBundledUseMI(const TargetRegisterInfo *TRI,
|
2016-06-30 00:01:54 +00:00
|
|
|
const MachineInstr &MI, unsigned Reg,
|
2011-12-14 02:11:42 +00:00
|
|
|
unsigned &UseIdx, unsigned &Dist) {
|
|
|
|
Dist = 0;
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
MachineBasicBlock::const_instr_iterator II = ++MI.getIterator();
|
2011-12-14 02:11:42 +00:00
|
|
|
assert(II->isInsideBundle() && "Empty bundle?");
|
2016-06-30 00:01:54 +00:00
|
|
|
MachineBasicBlock::const_instr_iterator E = MI.getParent()->instr_end();
|
2011-12-14 02:11:42 +00:00
|
|
|
|
|
|
|
// FIXME: This doesn't properly handle multiple uses.
|
|
|
|
int Idx = -1;
|
|
|
|
while (II != E && II->isInsideBundle()) {
|
|
|
|
Idx = II->findRegisterUseOperandIdx(Reg, false, TRI);
|
|
|
|
if (Idx != -1)
|
|
|
|
break;
|
|
|
|
if (II->getOpcode() != ARM::t2IT)
|
|
|
|
++Dist;
|
|
|
|
++II;
|
|
|
|
}
|
|
|
|
|
2011-12-14 20:00:08 +00:00
|
|
|
if (Idx == -1) {
|
|
|
|
Dist = 0;
|
2014-04-25 05:30:21 +00:00
|
|
|
return nullptr;
|
2011-12-14 20:00:08 +00:00
|
|
|
}
|
|
|
|
|
2011-12-14 02:11:42 +00:00
|
|
|
UseIdx = Idx;
|
2015-10-19 23:25:57 +00:00
|
|
|
return &*II;
|
2011-12-14 02:11:42 +00:00
|
|
|
}
|
|
|
|
|
2012-06-07 19:42:00 +00:00
|
|
|
/// Return the number of cycles to add to (or subtract from) the static
|
|
|
|
/// itinerary based on the def opcode and alignment. The caller will ensure that
|
|
|
|
/// adjusted latency is at least one cycle.
|
|
|
|
static int adjustDefLatency(const ARMSubtarget &Subtarget,
|
2016-06-30 00:01:54 +00:00
|
|
|
const MachineInstr &DefMI,
|
|
|
|
const MCInstrDesc &DefMCID, unsigned DefAlign) {
|
2012-06-07 19:42:00 +00:00
|
|
|
int Adjust = 0;
|
2014-04-01 14:10:07 +00:00
|
|
|
if (Subtarget.isCortexA8() || Subtarget.isLikeA9() || Subtarget.isCortexA7()) {
|
2010-10-28 06:47:08 +00:00
|
|
|
// FIXME: Shifter op hack: no shift (i.e. [r +/- r]) or [r + r << 2]
|
|
|
|
// variants are one cycle cheaper.
|
2016-06-30 00:01:54 +00:00
|
|
|
switch (DefMCID.getOpcode()) {
|
2010-10-28 06:47:08 +00:00
|
|
|
default: break;
|
2012-08-28 03:11:27 +00:00
|
|
|
case ARM::LDRrs:
|
|
|
|
case ARM::LDRBrs: {
|
2016-06-30 00:01:54 +00:00
|
|
|
unsigned ShOpVal = DefMI.getOperand(3).getImm();
|
2010-10-28 06:47:08 +00:00
|
|
|
unsigned ShImm = ARM_AM::getAM2Offset(ShOpVal);
|
|
|
|
if (ShImm == 0 ||
|
|
|
|
(ShImm == 2 && ARM_AM::getAM2ShiftOpc(ShOpVal) == ARM_AM::lsl))
|
2012-06-07 19:42:00 +00:00
|
|
|
--Adjust;
|
2010-10-28 06:47:08 +00:00
|
|
|
break;
|
|
|
|
}
|
2012-08-28 03:11:27 +00:00
|
|
|
case ARM::t2LDRs:
|
|
|
|
case ARM::t2LDRBs:
|
|
|
|
case ARM::t2LDRHs:
|
2010-10-28 06:47:08 +00:00
|
|
|
case ARM::t2LDRSHs: {
|
|
|
|
// Thumb2 mode: lsl only.
|
2016-06-30 00:01:54 +00:00
|
|
|
unsigned ShAmt = DefMI.getOperand(3).getImm();
|
2010-10-28 06:47:08 +00:00
|
|
|
if (ShAmt == 0 || ShAmt == 2)
|
2012-06-07 19:42:00 +00:00
|
|
|
--Adjust;
|
2010-10-28 06:47:08 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2012-09-29 21:43:49 +00:00
|
|
|
} else if (Subtarget.isSwift()) {
|
|
|
|
// FIXME: Properly handle all of the latency adjustments for address
|
|
|
|
// writeback.
|
2016-06-30 00:01:54 +00:00
|
|
|
switch (DefMCID.getOpcode()) {
|
2012-09-29 21:43:49 +00:00
|
|
|
default: break;
|
|
|
|
case ARM::LDRrs:
|
|
|
|
case ARM::LDRBrs: {
|
2016-06-30 00:01:54 +00:00
|
|
|
unsigned ShOpVal = DefMI.getOperand(3).getImm();
|
2012-09-29 21:43:49 +00:00
|
|
|
bool isSub = ARM_AM::getAM2Op(ShOpVal) == ARM_AM::sub;
|
|
|
|
unsigned ShImm = ARM_AM::getAM2Offset(ShOpVal);
|
|
|
|
if (!isSub &&
|
|
|
|
(ShImm == 0 ||
|
|
|
|
((ShImm == 1 || ShImm == 2 || ShImm == 3) &&
|
|
|
|
ARM_AM::getAM2ShiftOpc(ShOpVal) == ARM_AM::lsl)))
|
|
|
|
Adjust -= 2;
|
|
|
|
else if (!isSub &&
|
|
|
|
ShImm == 1 && ARM_AM::getAM2ShiftOpc(ShOpVal) == ARM_AM::lsr)
|
|
|
|
--Adjust;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case ARM::t2LDRs:
|
|
|
|
case ARM::t2LDRBs:
|
|
|
|
case ARM::t2LDRHs:
|
|
|
|
case ARM::t2LDRSHs: {
|
|
|
|
// Thumb2 mode: lsl only.
|
2016-06-30 00:01:54 +00:00
|
|
|
unsigned ShAmt = DefMI.getOperand(3).getImm();
|
2012-09-29 21:43:49 +00:00
|
|
|
if (ShAmt == 0 || ShAmt == 1 || ShAmt == 2 || ShAmt == 3)
|
|
|
|
Adjust -= 2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2010-10-28 06:47:08 +00:00
|
|
|
}
|
|
|
|
|
2016-06-27 09:08:23 +00:00
|
|
|
if (DefAlign < 8 && Subtarget.checkVLDnAccessAlignment()) {
|
2016-06-30 00:01:54 +00:00
|
|
|
switch (DefMCID.getOpcode()) {
|
2011-04-19 01:21:49 +00:00
|
|
|
default: break;
|
|
|
|
case ARM::VLD1q8:
|
|
|
|
case ARM::VLD1q16:
|
|
|
|
case ARM::VLD1q32:
|
|
|
|
case ARM::VLD1q64:
|
2011-10-24 21:45:13 +00:00
|
|
|
case ARM::VLD1q8wb_fixed:
|
|
|
|
case ARM::VLD1q16wb_fixed:
|
|
|
|
case ARM::VLD1q32wb_fixed:
|
|
|
|
case ARM::VLD1q64wb_fixed:
|
|
|
|
case ARM::VLD1q8wb_register:
|
|
|
|
case ARM::VLD1q16wb_register:
|
|
|
|
case ARM::VLD1q32wb_register:
|
|
|
|
case ARM::VLD1q64wb_register:
|
2011-04-19 01:21:49 +00:00
|
|
|
case ARM::VLD2d8:
|
|
|
|
case ARM::VLD2d16:
|
|
|
|
case ARM::VLD2d32:
|
|
|
|
case ARM::VLD2q8:
|
|
|
|
case ARM::VLD2q16:
|
|
|
|
case ARM::VLD2q32:
|
2011-12-09 21:28:25 +00:00
|
|
|
case ARM::VLD2d8wb_fixed:
|
|
|
|
case ARM::VLD2d16wb_fixed:
|
|
|
|
case ARM::VLD2d32wb_fixed:
|
|
|
|
case ARM::VLD2q8wb_fixed:
|
|
|
|
case ARM::VLD2q16wb_fixed:
|
|
|
|
case ARM::VLD2q32wb_fixed:
|
|
|
|
case ARM::VLD2d8wb_register:
|
|
|
|
case ARM::VLD2d16wb_register:
|
|
|
|
case ARM::VLD2d32wb_register:
|
|
|
|
case ARM::VLD2q8wb_register:
|
|
|
|
case ARM::VLD2q16wb_register:
|
|
|
|
case ARM::VLD2q32wb_register:
|
2011-04-19 01:21:49 +00:00
|
|
|
case ARM::VLD3d8:
|
|
|
|
case ARM::VLD3d16:
|
|
|
|
case ARM::VLD3d32:
|
|
|
|
case ARM::VLD1d64T:
|
|
|
|
case ARM::VLD3d8_UPD:
|
|
|
|
case ARM::VLD3d16_UPD:
|
|
|
|
case ARM::VLD3d32_UPD:
|
2011-10-24 23:26:05 +00:00
|
|
|
case ARM::VLD1d64Twb_fixed:
|
|
|
|
case ARM::VLD1d64Twb_register:
|
2011-04-19 01:21:49 +00:00
|
|
|
case ARM::VLD3q8_UPD:
|
|
|
|
case ARM::VLD3q16_UPD:
|
|
|
|
case ARM::VLD3q32_UPD:
|
|
|
|
case ARM::VLD4d8:
|
|
|
|
case ARM::VLD4d16:
|
|
|
|
case ARM::VLD4d32:
|
|
|
|
case ARM::VLD1d64Q:
|
|
|
|
case ARM::VLD4d8_UPD:
|
|
|
|
case ARM::VLD4d16_UPD:
|
|
|
|
case ARM::VLD4d32_UPD:
|
2011-10-25 00:14:01 +00:00
|
|
|
case ARM::VLD1d64Qwb_fixed:
|
|
|
|
case ARM::VLD1d64Qwb_register:
|
2011-04-19 01:21:49 +00:00
|
|
|
case ARM::VLD4q8_UPD:
|
|
|
|
case ARM::VLD4q16_UPD:
|
|
|
|
case ARM::VLD4q32_UPD:
|
|
|
|
case ARM::VLD1DUPq8:
|
|
|
|
case ARM::VLD1DUPq16:
|
|
|
|
case ARM::VLD1DUPq32:
|
2011-11-30 19:35:44 +00:00
|
|
|
case ARM::VLD1DUPq8wb_fixed:
|
|
|
|
case ARM::VLD1DUPq16wb_fixed:
|
|
|
|
case ARM::VLD1DUPq32wb_fixed:
|
|
|
|
case ARM::VLD1DUPq8wb_register:
|
|
|
|
case ARM::VLD1DUPq16wb_register:
|
|
|
|
case ARM::VLD1DUPq32wb_register:
|
2011-04-19 01:21:49 +00:00
|
|
|
case ARM::VLD2DUPd8:
|
|
|
|
case ARM::VLD2DUPd16:
|
|
|
|
case ARM::VLD2DUPd32:
|
2011-12-21 19:40:55 +00:00
|
|
|
case ARM::VLD2DUPd8wb_fixed:
|
|
|
|
case ARM::VLD2DUPd16wb_fixed:
|
|
|
|
case ARM::VLD2DUPd32wb_fixed:
|
|
|
|
case ARM::VLD2DUPd8wb_register:
|
|
|
|
case ARM::VLD2DUPd16wb_register:
|
|
|
|
case ARM::VLD2DUPd32wb_register:
|
2011-04-19 01:21:49 +00:00
|
|
|
case ARM::VLD4DUPd8:
|
|
|
|
case ARM::VLD4DUPd16:
|
|
|
|
case ARM::VLD4DUPd32:
|
|
|
|
case ARM::VLD4DUPd8_UPD:
|
|
|
|
case ARM::VLD4DUPd16_UPD:
|
|
|
|
case ARM::VLD4DUPd32_UPD:
|
|
|
|
case ARM::VLD1LNd8:
|
|
|
|
case ARM::VLD1LNd16:
|
|
|
|
case ARM::VLD1LNd32:
|
|
|
|
case ARM::VLD1LNd8_UPD:
|
|
|
|
case ARM::VLD1LNd16_UPD:
|
|
|
|
case ARM::VLD1LNd32_UPD:
|
|
|
|
case ARM::VLD2LNd8:
|
|
|
|
case ARM::VLD2LNd16:
|
|
|
|
case ARM::VLD2LNd32:
|
|
|
|
case ARM::VLD2LNq16:
|
|
|
|
case ARM::VLD2LNq32:
|
|
|
|
case ARM::VLD2LNd8_UPD:
|
|
|
|
case ARM::VLD2LNd16_UPD:
|
|
|
|
case ARM::VLD2LNd32_UPD:
|
|
|
|
case ARM::VLD2LNq16_UPD:
|
|
|
|
case ARM::VLD2LNq32_UPD:
|
|
|
|
case ARM::VLD4LNd8:
|
|
|
|
case ARM::VLD4LNd16:
|
|
|
|
case ARM::VLD4LNd32:
|
|
|
|
case ARM::VLD4LNq16:
|
|
|
|
case ARM::VLD4LNq32:
|
|
|
|
case ARM::VLD4LNd8_UPD:
|
|
|
|
case ARM::VLD4LNd16_UPD:
|
|
|
|
case ARM::VLD4LNd32_UPD:
|
|
|
|
case ARM::VLD4LNq16_UPD:
|
|
|
|
case ARM::VLD4LNq32_UPD:
|
|
|
|
// If the address is not 64-bit aligned, the latencies of these
|
|
|
|
// instructions increases by one.
|
2012-06-07 19:42:00 +00:00
|
|
|
++Adjust;
|
2011-04-19 01:21:49 +00:00
|
|
|
break;
|
|
|
|
}
|
2012-06-07 19:42:00 +00:00
|
|
|
}
|
|
|
|
return Adjust;
|
|
|
|
}
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
int ARMBaseInstrInfo::getOperandLatency(const InstrItineraryData *ItinData,
|
|
|
|
const MachineInstr &DefMI,
|
|
|
|
unsigned DefIdx,
|
|
|
|
const MachineInstr &UseMI,
|
|
|
|
unsigned UseIdx) const {
|
2012-06-07 19:42:00 +00:00
|
|
|
// No operand latency. The caller may fall back to getInstrLatency.
|
|
|
|
if (!ItinData || ItinData->isEmpty())
|
|
|
|
return -1;
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
const MachineOperand &DefMO = DefMI.getOperand(DefIdx);
|
Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Partial reverts in:
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
X86FixupLEAs.cpp - Some functions return unsigned and arguably should be MCRegister
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
HexagonBitSimplify.cpp - Function takes BitTracker::RegisterRef which appears to be unsigned&
MachineVerifier.cpp - Ambiguous operator==() given MCRegister and const Register
PPCFastISel.cpp - No Register::operator-=()
PeepholeOptimizer.cpp - TargetInstrInfo::optimizeLoadInstr() takes an unsigned&
MachineTraceMetrics.cpp - MachineTraceMetrics lacks a suitable constructor
Manual fixups in:
ARMFastISel.cpp - ARMEmitLoad() now takes a Register& instead of unsigned&
HexagonSplitDouble.cpp - Ternary operator was ambiguous between unsigned/Register
HexagonConstExtenders.cpp - Has a local class named Register, used llvm::Register instead of Register.
PPCFastISel.cpp - PPCEmitLoad() now takes a Register& instead of unsigned&
Depends on D65919
Reviewers: arsenm, bogner, craig.topper, RKSimon
Reviewed By: arsenm
Subscribers: RKSimon, craig.topper, lenary, aemerson, wuzish, jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65962
llvm-svn: 369041
2019-08-15 19:22:08 +00:00
|
|
|
Register Reg = DefMO.getReg();
|
2012-06-07 19:42:00 +00:00
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
const MachineInstr *ResolvedDefMI = &DefMI;
|
2012-06-07 19:42:00 +00:00
|
|
|
unsigned DefAdj = 0;
|
2016-06-30 00:01:54 +00:00
|
|
|
if (DefMI.isBundle())
|
|
|
|
ResolvedDefMI =
|
|
|
|
getBundledDefMI(&getRegisterInfo(), &DefMI, Reg, DefIdx, DefAdj);
|
|
|
|
if (ResolvedDefMI->isCopyLike() || ResolvedDefMI->isInsertSubreg() ||
|
|
|
|
ResolvedDefMI->isRegSequence() || ResolvedDefMI->isImplicitDef()) {
|
2012-06-07 19:42:00 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
const MachineInstr *ResolvedUseMI = &UseMI;
|
2012-06-07 19:42:00 +00:00
|
|
|
unsigned UseAdj = 0;
|
2016-06-30 00:01:54 +00:00
|
|
|
if (UseMI.isBundle()) {
|
|
|
|
ResolvedUseMI =
|
|
|
|
getBundledUseMI(&getRegisterInfo(), UseMI, Reg, UseIdx, UseAdj);
|
|
|
|
if (!ResolvedUseMI)
|
2012-06-22 02:50:33 +00:00
|
|
|
return -1;
|
2012-06-07 19:42:00 +00:00
|
|
|
}
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
return getOperandLatencyImpl(
|
|
|
|
ItinData, *ResolvedDefMI, DefIdx, ResolvedDefMI->getDesc(), DefAdj, DefMO,
|
|
|
|
Reg, *ResolvedUseMI, UseIdx, ResolvedUseMI->getDesc(), UseAdj);
|
|
|
|
}
|
|
|
|
|
|
|
|
int ARMBaseInstrInfo::getOperandLatencyImpl(
|
|
|
|
const InstrItineraryData *ItinData, const MachineInstr &DefMI,
|
|
|
|
unsigned DefIdx, const MCInstrDesc &DefMCID, unsigned DefAdj,
|
|
|
|
const MachineOperand &DefMO, unsigned Reg, const MachineInstr &UseMI,
|
|
|
|
unsigned UseIdx, const MCInstrDesc &UseMCID, unsigned UseAdj) const {
|
2012-06-07 19:42:00 +00:00
|
|
|
if (Reg == ARM::CPSR) {
|
2016-06-30 00:01:54 +00:00
|
|
|
if (DefMI.getOpcode() == ARM::FMSTAT) {
|
2012-06-07 19:42:00 +00:00
|
|
|
// fpscr -> cpsr stalls over 20 cycles on A8 (and earlier?)
|
2012-09-13 15:05:10 +00:00
|
|
|
return Subtarget.isLikeA9() ? 1 : 20;
|
2012-06-07 19:42:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// CPSR set and branch can be paired in the same cycle.
|
2016-06-30 00:01:54 +00:00
|
|
|
if (UseMI.isBranch())
|
2012-06-07 19:42:00 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
// Otherwise it takes the instruction latency (generally one).
|
|
|
|
unsigned Latency = getInstrLatency(ItinData, DefMI);
|
|
|
|
|
|
|
|
// For Thumb2 and -Os, prefer scheduling CPSR setting instruction close to
|
|
|
|
// its uses. Instructions which are otherwise scheduled between them may
|
|
|
|
// incur a code size penalty (not able to use the CPSR setting 16-bit
|
|
|
|
// instructions).
|
|
|
|
if (Latency > 0 && Subtarget.isThumb2()) {
|
2016-06-30 00:01:54 +00:00
|
|
|
const MachineFunction *MF = DefMI.getParent()->getParent();
|
2019-04-04 22:40:06 +00:00
|
|
|
// FIXME: Use Function::hasOptSize().
|
2017-12-15 22:22:58 +00:00
|
|
|
if (MF->getFunction().hasFnAttribute(Attribute::OptimizeForSize))
|
2012-06-07 19:42:00 +00:00
|
|
|
--Latency;
|
|
|
|
}
|
|
|
|
return Latency;
|
|
|
|
}
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
if (DefMO.isImplicit() || UseMI.getOperand(UseIdx).isImplicit())
|
2012-06-22 02:50:33 +00:00
|
|
|
return -1;
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
unsigned DefAlign = DefMI.hasOneMemOperand()
|
[Alignment][NFC] MachineMemOperand::getAlign/getBaseAlign
Summary:
This is patch is part of a series to introduce an Alignment type.
See this thread for context: http://lists.llvm.org/pipermail/llvm-dev/2019-July/133851.html
See this patch for the introduction of the type: https://reviews.llvm.org/D64790
Reviewers: courbet
Subscribers: arsenm, dschuff, sdardis, nemanjai, jvesely, nhaehnle, sbc100, jgravelle-google, hiraditya, aheejin, kbarton, jrtc27, atanasyan, jfb, kerbowa, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D76925
2020-03-27 13:51:59 +00:00
|
|
|
? (*DefMI.memoperands_begin())->getAlign().value()
|
2016-06-30 00:01:54 +00:00
|
|
|
: 0;
|
|
|
|
unsigned UseAlign = UseMI.hasOneMemOperand()
|
[Alignment][NFC] MachineMemOperand::getAlign/getBaseAlign
Summary:
This is patch is part of a series to introduce an Alignment type.
See this thread for context: http://lists.llvm.org/pipermail/llvm-dev/2019-July/133851.html
See this patch for the introduction of the type: https://reviews.llvm.org/D64790
Reviewers: courbet
Subscribers: arsenm, dschuff, sdardis, nemanjai, jvesely, nhaehnle, sbc100, jgravelle-google, hiraditya, aheejin, kbarton, jrtc27, atanasyan, jfb, kerbowa, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D76925
2020-03-27 13:51:59 +00:00
|
|
|
? (*UseMI.memoperands_begin())->getAlign().value()
|
2016-06-30 00:01:54 +00:00
|
|
|
: 0;
|
2012-06-07 19:42:00 +00:00
|
|
|
|
|
|
|
// Get the itinerary's latency if possible, and handle variable_ops.
|
2016-06-30 00:01:54 +00:00
|
|
|
int Latency = getOperandLatency(ItinData, DefMCID, DefIdx, DefAlign, UseMCID,
|
|
|
|
UseIdx, UseAlign);
|
2012-06-07 19:42:00 +00:00
|
|
|
// Unable to find operand latency. The caller may resort to getInstrLatency.
|
|
|
|
if (Latency < 0)
|
|
|
|
return Latency;
|
|
|
|
|
|
|
|
// Adjust for IT block position.
|
|
|
|
int Adj = DefAdj + UseAdj;
|
|
|
|
|
|
|
|
// Adjust for dynamic def-side opcode variants not captured by the itinerary.
|
|
|
|
Adj += adjustDefLatency(Subtarget, DefMI, DefMCID, DefAlign);
|
|
|
|
if (Adj >= 0 || (int)Latency > -Adj) {
|
|
|
|
return Latency + Adj;
|
|
|
|
}
|
|
|
|
// Return the itinerary latency, which may be zero but not less than zero.
|
2010-10-28 06:47:08 +00:00
|
|
|
return Latency;
|
2010-10-06 06:27:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
ARMBaseInstrInfo::getOperandLatency(const InstrItineraryData *ItinData,
|
|
|
|
SDNode *DefNode, unsigned DefIdx,
|
|
|
|
SDNode *UseNode, unsigned UseIdx) const {
|
|
|
|
if (!DefNode->isMachineOpcode())
|
|
|
|
return 1;
|
|
|
|
|
2011-06-28 19:10:37 +00:00
|
|
|
const MCInstrDesc &DefMCID = get(DefNode->getMachineOpcode());
|
2011-01-21 05:51:33 +00:00
|
|
|
|
2011-06-28 19:10:37 +00:00
|
|
|
if (isZeroCost(DefMCID.Opcode))
|
2011-01-21 05:51:33 +00:00
|
|
|
return 0;
|
|
|
|
|
2010-10-06 06:27:31 +00:00
|
|
|
if (!ItinData || ItinData->isEmpty())
|
2011-06-28 19:10:37 +00:00
|
|
|
return DefMCID.mayLoad() ? 3 : 1;
|
2010-10-06 06:27:31 +00:00
|
|
|
|
Avoiding overly aggressive latency scheduling. If the two nodes share an
operand and one of them has a single use that is a live out copy, favor the
one that is live out. Otherwise it will be difficult to eliminate the copy
if the instruction is a loop induction variable update. e.g.
BB:
sub r1, r3, #1
str r0, [r2, r3]
mov r3, r1
cmp
bne BB
=>
BB:
str r0, [r2, r3]
sub r3, r3, #1
cmp
bne BB
This fixed the recent 256.bzip2 regression.
llvm-svn: 117675
2010-10-29 18:09:28 +00:00
|
|
|
if (!UseNode->isMachineOpcode()) {
|
2011-06-28 19:10:37 +00:00
|
|
|
int Latency = ItinData->getOperandCycle(DefMCID.getSchedClass(), DefIdx);
|
2016-06-27 09:08:23 +00:00
|
|
|
int Adj = Subtarget.getPreISelOperandLatencyAdjustment();
|
|
|
|
int Threshold = 1 + Adj;
|
|
|
|
return Latency <= Threshold ? 1 : Latency - Adj;
|
Avoiding overly aggressive latency scheduling. If the two nodes share an
operand and one of them has a single use that is a live out copy, favor the
one that is live out. Otherwise it will be difficult to eliminate the copy
if the instruction is a loop induction variable update. e.g.
BB:
sub r1, r3, #1
str r0, [r2, r3]
mov r3, r1
cmp
bne BB
=>
BB:
str r0, [r2, r3]
sub r3, r3, #1
cmp
bne BB
This fixed the recent 256.bzip2 regression.
llvm-svn: 117675
2010-10-29 18:09:28 +00:00
|
|
|
}
|
2010-10-06 06:27:31 +00:00
|
|
|
|
2011-06-28 19:10:37 +00:00
|
|
|
const MCInstrDesc &UseMCID = get(UseNode->getMachineOpcode());
|
2019-09-26 16:05:55 +00:00
|
|
|
auto *DefMN = cast<MachineSDNode>(DefNode);
|
2010-10-06 06:27:31 +00:00
|
|
|
unsigned DefAlign = !DefMN->memoperands_empty()
|
[Alignment][NFC] MachineMemOperand::getAlign/getBaseAlign
Summary:
This is patch is part of a series to introduce an Alignment type.
See this thread for context: http://lists.llvm.org/pipermail/llvm-dev/2019-July/133851.html
See this patch for the introduction of the type: https://reviews.llvm.org/D64790
Reviewers: courbet
Subscribers: arsenm, dschuff, sdardis, nemanjai, jvesely, nhaehnle, sbc100, jgravelle-google, hiraditya, aheejin, kbarton, jrtc27, atanasyan, jfb, kerbowa, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D76925
2020-03-27 13:51:59 +00:00
|
|
|
? (*DefMN->memoperands_begin())->getAlign().value()
|
|
|
|
: 0;
|
2019-09-26 16:05:55 +00:00
|
|
|
auto *UseMN = cast<MachineSDNode>(UseNode);
|
2010-10-06 06:27:31 +00:00
|
|
|
unsigned UseAlign = !UseMN->memoperands_empty()
|
[Alignment][NFC] MachineMemOperand::getAlign/getBaseAlign
Summary:
This is patch is part of a series to introduce an Alignment type.
See this thread for context: http://lists.llvm.org/pipermail/llvm-dev/2019-July/133851.html
See this patch for the introduction of the type: https://reviews.llvm.org/D64790
Reviewers: courbet
Subscribers: arsenm, dschuff, sdardis, nemanjai, jvesely, nhaehnle, sbc100, jgravelle-google, hiraditya, aheejin, kbarton, jrtc27, atanasyan, jfb, kerbowa, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D76925
2020-03-27 13:51:59 +00:00
|
|
|
? (*UseMN->memoperands_begin())->getAlign().value()
|
|
|
|
: 0;
|
2011-06-28 19:10:37 +00:00
|
|
|
int Latency = getOperandLatency(ItinData, DefMCID, DefIdx, DefAlign,
|
|
|
|
UseMCID, UseIdx, UseAlign);
|
2010-10-28 06:47:08 +00:00
|
|
|
|
|
|
|
if (Latency > 1 &&
|
2014-04-01 14:10:07 +00:00
|
|
|
(Subtarget.isCortexA8() || Subtarget.isLikeA9() ||
|
|
|
|
Subtarget.isCortexA7())) {
|
2010-10-28 06:47:08 +00:00
|
|
|
// FIXME: Shifter op hack: no shift (i.e. [r +/- r]) or [r + r << 2]
|
|
|
|
// variants are one cycle cheaper.
|
2011-06-28 19:10:37 +00:00
|
|
|
switch (DefMCID.getOpcode()) {
|
2010-10-28 06:47:08 +00:00
|
|
|
default: break;
|
2012-08-28 03:11:27 +00:00
|
|
|
case ARM::LDRrs:
|
|
|
|
case ARM::LDRBrs: {
|
2010-10-28 06:47:08 +00:00
|
|
|
unsigned ShOpVal =
|
|
|
|
cast<ConstantSDNode>(DefNode->getOperand(2))->getZExtValue();
|
|
|
|
unsigned ShImm = ARM_AM::getAM2Offset(ShOpVal);
|
|
|
|
if (ShImm == 0 ||
|
|
|
|
(ShImm == 2 && ARM_AM::getAM2ShiftOpc(ShOpVal) == ARM_AM::lsl))
|
|
|
|
--Latency;
|
|
|
|
break;
|
|
|
|
}
|
2012-08-28 03:11:27 +00:00
|
|
|
case ARM::t2LDRs:
|
|
|
|
case ARM::t2LDRBs:
|
|
|
|
case ARM::t2LDRHs:
|
2010-10-28 06:47:08 +00:00
|
|
|
case ARM::t2LDRSHs: {
|
|
|
|
// Thumb2 mode: lsl only.
|
|
|
|
unsigned ShAmt =
|
|
|
|
cast<ConstantSDNode>(DefNode->getOperand(2))->getZExtValue();
|
|
|
|
if (ShAmt == 0 || ShAmt == 2)
|
|
|
|
--Latency;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2012-09-29 21:43:49 +00:00
|
|
|
} else if (DefIdx == 0 && Latency > 2 && Subtarget.isSwift()) {
|
|
|
|
// FIXME: Properly handle all of the latency adjustments for address
|
|
|
|
// writeback.
|
|
|
|
switch (DefMCID.getOpcode()) {
|
|
|
|
default: break;
|
|
|
|
case ARM::LDRrs:
|
|
|
|
case ARM::LDRBrs: {
|
|
|
|
unsigned ShOpVal =
|
|
|
|
cast<ConstantSDNode>(DefNode->getOperand(2))->getZExtValue();
|
|
|
|
unsigned ShImm = ARM_AM::getAM2Offset(ShOpVal);
|
|
|
|
if (ShImm == 0 ||
|
|
|
|
((ShImm == 1 || ShImm == 2 || ShImm == 3) &&
|
|
|
|
ARM_AM::getAM2ShiftOpc(ShOpVal) == ARM_AM::lsl))
|
|
|
|
Latency -= 2;
|
|
|
|
else if (ShImm == 1 && ARM_AM::getAM2ShiftOpc(ShOpVal) == ARM_AM::lsr)
|
|
|
|
--Latency;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case ARM::t2LDRs:
|
|
|
|
case ARM::t2LDRBs:
|
|
|
|
case ARM::t2LDRHs:
|
2017-01-26 23:40:06 +00:00
|
|
|
case ARM::t2LDRSHs:
|
2012-09-29 21:43:49 +00:00
|
|
|
// Thumb2 mode: lsl 0-3 only.
|
|
|
|
Latency -= 2;
|
|
|
|
break;
|
|
|
|
}
|
2010-10-28 06:47:08 +00:00
|
|
|
}
|
|
|
|
|
2016-06-27 09:08:23 +00:00
|
|
|
if (DefAlign < 8 && Subtarget.checkVLDnAccessAlignment())
|
2011-06-28 19:10:37 +00:00
|
|
|
switch (DefMCID.getOpcode()) {
|
2011-04-19 01:21:49 +00:00
|
|
|
default: break;
|
2012-03-05 19:33:30 +00:00
|
|
|
case ARM::VLD1q8:
|
|
|
|
case ARM::VLD1q16:
|
|
|
|
case ARM::VLD1q32:
|
|
|
|
case ARM::VLD1q64:
|
|
|
|
case ARM::VLD1q8wb_register:
|
|
|
|
case ARM::VLD1q16wb_register:
|
|
|
|
case ARM::VLD1q32wb_register:
|
|
|
|
case ARM::VLD1q64wb_register:
|
|
|
|
case ARM::VLD1q8wb_fixed:
|
|
|
|
case ARM::VLD1q16wb_fixed:
|
|
|
|
case ARM::VLD1q32wb_fixed:
|
|
|
|
case ARM::VLD1q64wb_fixed:
|
|
|
|
case ARM::VLD2d8:
|
|
|
|
case ARM::VLD2d16:
|
|
|
|
case ARM::VLD2d32:
|
2011-04-19 01:21:49 +00:00
|
|
|
case ARM::VLD2q8Pseudo:
|
|
|
|
case ARM::VLD2q16Pseudo:
|
|
|
|
case ARM::VLD2q32Pseudo:
|
2012-03-05 19:33:30 +00:00
|
|
|
case ARM::VLD2d8wb_fixed:
|
|
|
|
case ARM::VLD2d16wb_fixed:
|
|
|
|
case ARM::VLD2d32wb_fixed:
|
2011-12-09 21:28:25 +00:00
|
|
|
case ARM::VLD2q8PseudoWB_fixed:
|
|
|
|
case ARM::VLD2q16PseudoWB_fixed:
|
|
|
|
case ARM::VLD2q32PseudoWB_fixed:
|
2012-03-05 19:33:30 +00:00
|
|
|
case ARM::VLD2d8wb_register:
|
|
|
|
case ARM::VLD2d16wb_register:
|
|
|
|
case ARM::VLD2d32wb_register:
|
2011-12-09 21:28:25 +00:00
|
|
|
case ARM::VLD2q8PseudoWB_register:
|
|
|
|
case ARM::VLD2q16PseudoWB_register:
|
|
|
|
case ARM::VLD2q32PseudoWB_register:
|
2011-04-19 01:21:49 +00:00
|
|
|
case ARM::VLD3d8Pseudo:
|
|
|
|
case ARM::VLD3d16Pseudo:
|
|
|
|
case ARM::VLD3d32Pseudo:
|
2018-06-02 16:40:03 +00:00
|
|
|
case ARM::VLD1d8TPseudo:
|
|
|
|
case ARM::VLD1d16TPseudo:
|
|
|
|
case ARM::VLD1d32TPseudo:
|
2011-04-19 01:21:49 +00:00
|
|
|
case ARM::VLD1d64TPseudo:
|
2014-01-16 09:16:13 +00:00
|
|
|
case ARM::VLD1d64TPseudoWB_fixed:
|
2018-03-02 13:02:55 +00:00
|
|
|
case ARM::VLD1d64TPseudoWB_register:
|
2011-04-19 01:21:49 +00:00
|
|
|
case ARM::VLD3d8Pseudo_UPD:
|
|
|
|
case ARM::VLD3d16Pseudo_UPD:
|
|
|
|
case ARM::VLD3d32Pseudo_UPD:
|
|
|
|
case ARM::VLD3q8Pseudo_UPD:
|
|
|
|
case ARM::VLD3q16Pseudo_UPD:
|
|
|
|
case ARM::VLD3q32Pseudo_UPD:
|
|
|
|
case ARM::VLD3q8oddPseudo:
|
|
|
|
case ARM::VLD3q16oddPseudo:
|
|
|
|
case ARM::VLD3q32oddPseudo:
|
|
|
|
case ARM::VLD3q8oddPseudo_UPD:
|
|
|
|
case ARM::VLD3q16oddPseudo_UPD:
|
|
|
|
case ARM::VLD3q32oddPseudo_UPD:
|
|
|
|
case ARM::VLD4d8Pseudo:
|
|
|
|
case ARM::VLD4d16Pseudo:
|
|
|
|
case ARM::VLD4d32Pseudo:
|
2018-06-02 16:40:03 +00:00
|
|
|
case ARM::VLD1d8QPseudo:
|
|
|
|
case ARM::VLD1d16QPseudo:
|
|
|
|
case ARM::VLD1d32QPseudo:
|
2011-04-19 01:21:49 +00:00
|
|
|
case ARM::VLD1d64QPseudo:
|
2014-01-16 09:16:13 +00:00
|
|
|
case ARM::VLD1d64QPseudoWB_fixed:
|
2018-03-02 13:02:55 +00:00
|
|
|
case ARM::VLD1d64QPseudoWB_register:
|
2018-06-02 16:40:03 +00:00
|
|
|
case ARM::VLD1q8HighQPseudo:
|
|
|
|
case ARM::VLD1q8LowQPseudo_UPD:
|
|
|
|
case ARM::VLD1q8HighTPseudo:
|
|
|
|
case ARM::VLD1q8LowTPseudo_UPD:
|
|
|
|
case ARM::VLD1q16HighQPseudo:
|
|
|
|
case ARM::VLD1q16LowQPseudo_UPD:
|
|
|
|
case ARM::VLD1q16HighTPseudo:
|
|
|
|
case ARM::VLD1q16LowTPseudo_UPD:
|
|
|
|
case ARM::VLD1q32HighQPseudo:
|
|
|
|
case ARM::VLD1q32LowQPseudo_UPD:
|
|
|
|
case ARM::VLD1q32HighTPseudo:
|
|
|
|
case ARM::VLD1q32LowTPseudo_UPD:
|
|
|
|
case ARM::VLD1q64HighQPseudo:
|
|
|
|
case ARM::VLD1q64LowQPseudo_UPD:
|
|
|
|
case ARM::VLD1q64HighTPseudo:
|
|
|
|
case ARM::VLD1q64LowTPseudo_UPD:
|
2011-04-19 01:21:49 +00:00
|
|
|
case ARM::VLD4d8Pseudo_UPD:
|
|
|
|
case ARM::VLD4d16Pseudo_UPD:
|
|
|
|
case ARM::VLD4d32Pseudo_UPD:
|
|
|
|
case ARM::VLD4q8Pseudo_UPD:
|
|
|
|
case ARM::VLD4q16Pseudo_UPD:
|
|
|
|
case ARM::VLD4q32Pseudo_UPD:
|
|
|
|
case ARM::VLD4q8oddPseudo:
|
|
|
|
case ARM::VLD4q16oddPseudo:
|
|
|
|
case ARM::VLD4q32oddPseudo:
|
|
|
|
case ARM::VLD4q8oddPseudo_UPD:
|
|
|
|
case ARM::VLD4q16oddPseudo_UPD:
|
|
|
|
case ARM::VLD4q32oddPseudo_UPD:
|
2012-03-06 22:01:44 +00:00
|
|
|
case ARM::VLD1DUPq8:
|
|
|
|
case ARM::VLD1DUPq16:
|
|
|
|
case ARM::VLD1DUPq32:
|
|
|
|
case ARM::VLD1DUPq8wb_fixed:
|
|
|
|
case ARM::VLD1DUPq16wb_fixed:
|
|
|
|
case ARM::VLD1DUPq32wb_fixed:
|
|
|
|
case ARM::VLD1DUPq8wb_register:
|
|
|
|
case ARM::VLD1DUPq16wb_register:
|
|
|
|
case ARM::VLD1DUPq32wb_register:
|
|
|
|
case ARM::VLD2DUPd8:
|
|
|
|
case ARM::VLD2DUPd16:
|
|
|
|
case ARM::VLD2DUPd32:
|
|
|
|
case ARM::VLD2DUPd8wb_fixed:
|
|
|
|
case ARM::VLD2DUPd16wb_fixed:
|
|
|
|
case ARM::VLD2DUPd32wb_fixed:
|
|
|
|
case ARM::VLD2DUPd8wb_register:
|
|
|
|
case ARM::VLD2DUPd16wb_register:
|
|
|
|
case ARM::VLD2DUPd32wb_register:
|
[NEON] Support vldNq intrinsics in AArch32 (LLVM part)
This patch adds support for the q versions of the dup
(load-to-all-lanes) NEON intrinsics, such as vld2q_dup_f16() for
example.
Currently, non-q versions of the dup intrinsics are implemented
in clang by generating IR that first loads the elements of the
structure into the first lane with the lane (to-single-lane)
intrinsics, and then propagating it other lanes. There are at
least two problems with this approach. First, there are no
double-spaced to-single-lane byte-element instructions. For
example, there is no such instruction as 'vld2.8 { d0[0], d2[0]
}, [r0]'. That means we cannot rely on the to-single-lane
intrinsics and instructions to implement the q versions of the
dup intrinsics. Note that to-all-lanes instructions do support
all sizes of data items, including bytes.
The second problem with the current approach is that we need a
separate vdup instruction to propagate the structure to each
lane. So for vld4q_dup_f16() we would need four vdup instructions
in addition to the initial vld instruction.
This patch introduces dup LLVM intrinsics and reworks handling of
the currently supported (non-q) NEON dup intrinsics to expand
them into those LLVM intrinsics, thus eliminating the need for
using to-single-lane intrinsics and instructions.
Additionally, this patch adds support for u64 and s64 dup NEON
intrinsics. These are marked as Arch64-only in the ARM NEON
Reference, but it seems there are no reasons to not support them
in AArch32 mode. Please correct, if that is wrong.
That's what we generate with this patch applied:
vld2q_dup_f16:
vld2.16 {d0[], d2[]}, [r0]
vld2.16 {d1[], d3[]}, [r0]
vld3q_dup_f16:
vld3.16 {d0[], d2[], d4[]}, [r0]
vld3.16 {d1[], d3[], d5[]}, [r0]
vld4q_dup_f16:
vld4.16 {d0[], d2[], d4[], d6[]}, [r0]
vld4.16 {d1[], d3[], d5[], d7[]}, [r0]
Differential Revision: https://reviews.llvm.org/D48439
llvm-svn: 335733
2018-06-27 13:57:52 +00:00
|
|
|
case ARM::VLD2DUPq8EvenPseudo:
|
|
|
|
case ARM::VLD2DUPq8OddPseudo:
|
|
|
|
case ARM::VLD2DUPq16EvenPseudo:
|
|
|
|
case ARM::VLD2DUPq16OddPseudo:
|
|
|
|
case ARM::VLD2DUPq32EvenPseudo:
|
|
|
|
case ARM::VLD2DUPq32OddPseudo:
|
|
|
|
case ARM::VLD3DUPq8EvenPseudo:
|
|
|
|
case ARM::VLD3DUPq8OddPseudo:
|
|
|
|
case ARM::VLD3DUPq16EvenPseudo:
|
|
|
|
case ARM::VLD3DUPq16OddPseudo:
|
|
|
|
case ARM::VLD3DUPq32EvenPseudo:
|
|
|
|
case ARM::VLD3DUPq32OddPseudo:
|
2011-04-19 01:21:49 +00:00
|
|
|
case ARM::VLD4DUPd8Pseudo:
|
|
|
|
case ARM::VLD4DUPd16Pseudo:
|
|
|
|
case ARM::VLD4DUPd32Pseudo:
|
|
|
|
case ARM::VLD4DUPd8Pseudo_UPD:
|
|
|
|
case ARM::VLD4DUPd16Pseudo_UPD:
|
|
|
|
case ARM::VLD4DUPd32Pseudo_UPD:
|
[NEON] Support vldNq intrinsics in AArch32 (LLVM part)
This patch adds support for the q versions of the dup
(load-to-all-lanes) NEON intrinsics, such as vld2q_dup_f16() for
example.
Currently, non-q versions of the dup intrinsics are implemented
in clang by generating IR that first loads the elements of the
structure into the first lane with the lane (to-single-lane)
intrinsics, and then propagating it other lanes. There are at
least two problems with this approach. First, there are no
double-spaced to-single-lane byte-element instructions. For
example, there is no such instruction as 'vld2.8 { d0[0], d2[0]
}, [r0]'. That means we cannot rely on the to-single-lane
intrinsics and instructions to implement the q versions of the
dup intrinsics. Note that to-all-lanes instructions do support
all sizes of data items, including bytes.
The second problem with the current approach is that we need a
separate vdup instruction to propagate the structure to each
lane. So for vld4q_dup_f16() we would need four vdup instructions
in addition to the initial vld instruction.
This patch introduces dup LLVM intrinsics and reworks handling of
the currently supported (non-q) NEON dup intrinsics to expand
them into those LLVM intrinsics, thus eliminating the need for
using to-single-lane intrinsics and instructions.
Additionally, this patch adds support for u64 and s64 dup NEON
intrinsics. These are marked as Arch64-only in the ARM NEON
Reference, but it seems there are no reasons to not support them
in AArch32 mode. Please correct, if that is wrong.
That's what we generate with this patch applied:
vld2q_dup_f16:
vld2.16 {d0[], d2[]}, [r0]
vld2.16 {d1[], d3[]}, [r0]
vld3q_dup_f16:
vld3.16 {d0[], d2[], d4[]}, [r0]
vld3.16 {d1[], d3[], d5[]}, [r0]
vld4q_dup_f16:
vld4.16 {d0[], d2[], d4[], d6[]}, [r0]
vld4.16 {d1[], d3[], d5[], d7[]}, [r0]
Differential Revision: https://reviews.llvm.org/D48439
llvm-svn: 335733
2018-06-27 13:57:52 +00:00
|
|
|
case ARM::VLD4DUPq8EvenPseudo:
|
|
|
|
case ARM::VLD4DUPq8OddPseudo:
|
|
|
|
case ARM::VLD4DUPq16EvenPseudo:
|
|
|
|
case ARM::VLD4DUPq16OddPseudo:
|
|
|
|
case ARM::VLD4DUPq32EvenPseudo:
|
|
|
|
case ARM::VLD4DUPq32OddPseudo:
|
2011-04-19 01:21:49 +00:00
|
|
|
case ARM::VLD1LNq8Pseudo:
|
|
|
|
case ARM::VLD1LNq16Pseudo:
|
|
|
|
case ARM::VLD1LNq32Pseudo:
|
|
|
|
case ARM::VLD1LNq8Pseudo_UPD:
|
|
|
|
case ARM::VLD1LNq16Pseudo_UPD:
|
|
|
|
case ARM::VLD1LNq32Pseudo_UPD:
|
|
|
|
case ARM::VLD2LNd8Pseudo:
|
|
|
|
case ARM::VLD2LNd16Pseudo:
|
|
|
|
case ARM::VLD2LNd32Pseudo:
|
|
|
|
case ARM::VLD2LNq16Pseudo:
|
|
|
|
case ARM::VLD2LNq32Pseudo:
|
|
|
|
case ARM::VLD2LNd8Pseudo_UPD:
|
|
|
|
case ARM::VLD2LNd16Pseudo_UPD:
|
|
|
|
case ARM::VLD2LNd32Pseudo_UPD:
|
|
|
|
case ARM::VLD2LNq16Pseudo_UPD:
|
|
|
|
case ARM::VLD2LNq32Pseudo_UPD:
|
|
|
|
case ARM::VLD4LNd8Pseudo:
|
|
|
|
case ARM::VLD4LNd16Pseudo:
|
|
|
|
case ARM::VLD4LNd32Pseudo:
|
|
|
|
case ARM::VLD4LNq16Pseudo:
|
|
|
|
case ARM::VLD4LNq32Pseudo:
|
|
|
|
case ARM::VLD4LNd8Pseudo_UPD:
|
|
|
|
case ARM::VLD4LNd16Pseudo_UPD:
|
|
|
|
case ARM::VLD4LNd32Pseudo_UPD:
|
|
|
|
case ARM::VLD4LNq16Pseudo_UPD:
|
|
|
|
case ARM::VLD4LNq32Pseudo_UPD:
|
|
|
|
// If the address is not 64-bit aligned, the latencies of these
|
|
|
|
// instructions increases by one.
|
|
|
|
++Latency;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-10-28 06:47:08 +00:00
|
|
|
return Latency;
|
2010-10-06 06:27:31 +00:00
|
|
|
}
|
2010-10-19 18:58:51 +00:00
|
|
|
|
2016-02-23 02:46:52 +00:00
|
|
|
unsigned ARMBaseInstrInfo::getPredicationCost(const MachineInstr &MI) const {
|
|
|
|
if (MI.isCopyLike() || MI.isInsertSubreg() || MI.isRegSequence() ||
|
|
|
|
MI.isImplicitDef())
|
2013-09-30 15:28:56 +00:00
|
|
|
return 0;
|
|
|
|
|
2016-02-23 02:46:52 +00:00
|
|
|
if (MI.isBundle())
|
2013-09-30 15:28:56 +00:00
|
|
|
return 0;
|
|
|
|
|
2016-02-23 02:46:52 +00:00
|
|
|
const MCInstrDesc &MCID = MI.getDesc();
|
2013-09-30 15:28:56 +00:00
|
|
|
|
2017-06-02 08:53:19 +00:00
|
|
|
if (MCID.isCall() || (MCID.hasImplicitDefOfPhysReg(ARM::CPSR) &&
|
|
|
|
!Subtarget.cheapPredicableCPSRDef())) {
|
2013-09-30 15:28:56 +00:00
|
|
|
// When predicated, CPSR is an additional source operand for CPSR updating
|
|
|
|
// instructions, this apparently increases their latencies.
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-06-05 21:11:27 +00:00
|
|
|
unsigned ARMBaseInstrInfo::getInstrLatency(const InstrItineraryData *ItinData,
|
2016-06-30 00:01:54 +00:00
|
|
|
const MachineInstr &MI,
|
2012-06-05 21:11:27 +00:00
|
|
|
unsigned *PredCost) const {
|
2016-06-30 00:01:54 +00:00
|
|
|
if (MI.isCopyLike() || MI.isInsertSubreg() || MI.isRegSequence() ||
|
|
|
|
MI.isImplicitDef())
|
2010-11-03 00:45:17 +00:00
|
|
|
return 1;
|
|
|
|
|
2012-06-07 19:41:55 +00:00
|
|
|
// An instruction scheduler typically runs on unbundled instructions, however
|
|
|
|
// other passes may query the latency of a bundled instruction.
|
2016-06-30 00:01:54 +00:00
|
|
|
if (MI.isBundle()) {
|
2012-06-07 19:41:55 +00:00
|
|
|
unsigned Latency = 0;
|
2016-06-30 00:01:54 +00:00
|
|
|
MachineBasicBlock::const_instr_iterator I = MI.getIterator();
|
|
|
|
MachineBasicBlock::const_instr_iterator E = MI.getParent()->instr_end();
|
2011-12-14 02:11:42 +00:00
|
|
|
while (++I != E && I->isInsideBundle()) {
|
|
|
|
if (I->getOpcode() != ARM::t2IT)
|
2016-06-30 00:01:54 +00:00
|
|
|
Latency += getInstrLatency(ItinData, *I, PredCost);
|
2011-12-14 02:11:42 +00:00
|
|
|
}
|
|
|
|
return Latency;
|
|
|
|
}
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
const MCInstrDesc &MCID = MI.getDesc();
|
2017-06-02 08:53:19 +00:00
|
|
|
if (PredCost && (MCID.isCall() || (MCID.hasImplicitDefOfPhysReg(ARM::CPSR) &&
|
|
|
|
!Subtarget.cheapPredicableCPSRDef()))) {
|
2010-11-03 00:45:17 +00:00
|
|
|
// When predicated, CPSR is an additional source operand for CPSR updating
|
|
|
|
// instructions, this apparently increases their latencies.
|
|
|
|
*PredCost = 1;
|
2012-06-07 19:41:55 +00:00
|
|
|
}
|
|
|
|
// Be sure to call getStageLatency for an empty itinerary in case it has a
|
|
|
|
// valid MinLatency property.
|
|
|
|
if (!ItinData)
|
2016-06-30 00:01:54 +00:00
|
|
|
return MI.mayLoad() ? 3 : 1;
|
2012-06-07 19:41:55 +00:00
|
|
|
|
|
|
|
unsigned Class = MCID.getSchedClass();
|
|
|
|
|
|
|
|
// For instructions with variable uops, use uops as latency.
|
2012-07-02 19:12:29 +00:00
|
|
|
if (!ItinData->isEmpty() && ItinData->getNumMicroOps(Class) < 0)
|
2012-06-07 19:41:55 +00:00
|
|
|
return getNumMicroOps(ItinData, MI);
|
2012-07-02 19:12:29 +00:00
|
|
|
|
2012-06-07 19:41:55 +00:00
|
|
|
// For the common case, fall back on the itinerary's latency.
|
2012-06-07 19:42:00 +00:00
|
|
|
unsigned Latency = ItinData->getStageLatency(Class);
|
|
|
|
|
|
|
|
// Adjust for dynamic def-side opcode variants not captured by the itinerary.
|
2016-06-30 00:01:54 +00:00
|
|
|
unsigned DefAlign =
|
[Alignment][NFC] MachineMemOperand::getAlign/getBaseAlign
Summary:
This is patch is part of a series to introduce an Alignment type.
See this thread for context: http://lists.llvm.org/pipermail/llvm-dev/2019-July/133851.html
See this patch for the introduction of the type: https://reviews.llvm.org/D64790
Reviewers: courbet
Subscribers: arsenm, dschuff, sdardis, nemanjai, jvesely, nhaehnle, sbc100, jgravelle-google, hiraditya, aheejin, kbarton, jrtc27, atanasyan, jfb, kerbowa, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D76925
2020-03-27 13:51:59 +00:00
|
|
|
MI.hasOneMemOperand() ? (*MI.memoperands_begin())->getAlign().value() : 0;
|
2016-06-30 00:01:54 +00:00
|
|
|
int Adj = adjustDefLatency(Subtarget, MI, MCID, DefAlign);
|
2012-06-07 19:42:00 +00:00
|
|
|
if (Adj >= 0 || (int)Latency > -Adj) {
|
|
|
|
return Latency + Adj;
|
|
|
|
}
|
|
|
|
return Latency;
|
2010-11-03 00:45:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int ARMBaseInstrInfo::getInstrLatency(const InstrItineraryData *ItinData,
|
|
|
|
SDNode *Node) const {
|
|
|
|
if (!Node->isMachineOpcode())
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (!ItinData || ItinData->isEmpty())
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
unsigned Opcode = Node->getMachineOpcode();
|
|
|
|
switch (Opcode) {
|
|
|
|
default:
|
|
|
|
return ItinData->getStageLatency(get(Opcode).getSchedClass());
|
2010-11-16 01:16:36 +00:00
|
|
|
case ARM::VLDMQIA:
|
|
|
|
case ARM::VSTMQIA:
|
2010-11-03 00:45:17 +00:00
|
|
|
return 2;
|
2010-11-18 19:40:05 +00:00
|
|
|
}
|
2010-11-03 00:45:17 +00:00
|
|
|
}
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
bool ARMBaseInstrInfo::hasHighOperandLatency(const TargetSchedModel &SchedModel,
|
|
|
|
const MachineRegisterInfo *MRI,
|
|
|
|
const MachineInstr &DefMI,
|
|
|
|
unsigned DefIdx,
|
|
|
|
const MachineInstr &UseMI,
|
|
|
|
unsigned UseIdx) const {
|
|
|
|
unsigned DDomain = DefMI.getDesc().TSFlags & ARMII::DomainMask;
|
|
|
|
unsigned UDomain = UseMI.getDesc().TSFlags & ARMII::DomainMask;
|
2016-06-27 09:08:23 +00:00
|
|
|
if (Subtarget.nonpipelinedVFP() &&
|
2010-10-19 18:58:51 +00:00
|
|
|
(DDomain == ARMII::DomainVFP || UDomain == ARMII::DomainVFP))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Hoist VFP / NEON instructions with 4 or higher latency.
|
2016-06-30 00:01:54 +00:00
|
|
|
unsigned Latency =
|
|
|
|
SchedModel.computeOperandLatency(&DefMI, DefIdx, &UseMI, UseIdx);
|
2010-10-19 18:58:51 +00:00
|
|
|
if (Latency <= 3)
|
|
|
|
return false;
|
|
|
|
return DDomain == ARMII::DomainVFP || DDomain == ARMII::DomainNEON ||
|
|
|
|
UDomain == ARMII::DomainVFP || UDomain == ARMII::DomainNEON;
|
|
|
|
}
|
2010-10-26 02:08:50 +00:00
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
bool ARMBaseInstrInfo::hasLowDefLatency(const TargetSchedModel &SchedModel,
|
|
|
|
const MachineInstr &DefMI,
|
|
|
|
unsigned DefIdx) const {
|
2015-06-13 03:42:11 +00:00
|
|
|
const InstrItineraryData *ItinData = SchedModel.getInstrItineraries();
|
2010-10-26 02:08:50 +00:00
|
|
|
if (!ItinData || ItinData->isEmpty())
|
|
|
|
return false;
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
unsigned DDomain = DefMI.getDesc().TSFlags & ARMII::DomainMask;
|
2010-10-26 02:08:50 +00:00
|
|
|
if (DDomain == ARMII::DomainGeneral) {
|
2016-06-30 00:01:54 +00:00
|
|
|
unsigned DefClass = DefMI.getDesc().getSchedClass();
|
2010-10-26 02:08:50 +00:00
|
|
|
int DefCycle = ItinData->getOperandCycle(DefClass, DefIdx);
|
|
|
|
return (DefCycle != -1 && DefCycle <= 2);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2010-12-05 22:04:16 +00:00
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
bool ARMBaseInstrInfo::verifyInstruction(const MachineInstr &MI,
|
2011-09-21 02:20:46 +00:00
|
|
|
StringRef &ErrInfo) const {
|
2016-06-30 00:01:54 +00:00
|
|
|
if (convertAddSubFlagsOpcode(MI.getOpcode())) {
|
2011-09-21 02:20:46 +00:00
|
|
|
ErrInfo = "Pseudo flag setting opcodes only exist in Selection DAG";
|
|
|
|
return false;
|
|
|
|
}
|
2019-03-15 21:44:49 +00:00
|
|
|
if (MI.getOpcode() == ARM::tMOVr && !Subtarget.hasV6Ops()) {
|
|
|
|
// Make sure we don't generate a lo-lo mov that isn't supported.
|
|
|
|
if (!ARM::hGPRRegClass.contains(MI.getOperand(0).getReg()) &&
|
|
|
|
!ARM::hGPRRegClass.contains(MI.getOperand(1).getReg())) {
|
|
|
|
ErrInfo = "Non-flag-setting Thumb1 mov is v6-only";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (MI.getOpcode() == ARM::tPUSH ||
|
|
|
|
MI.getOpcode() == ARM::tPOP ||
|
|
|
|
MI.getOpcode() == ARM::tPOP_RET) {
|
|
|
|
for (int i = 2, e = MI.getNumOperands(); i < e; ++i) {
|
|
|
|
if (MI.getOperand(i).isImplicit() ||
|
|
|
|
!MI.getOperand(i).isReg())
|
|
|
|
continue;
|
Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Partial reverts in:
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
X86FixupLEAs.cpp - Some functions return unsigned and arguably should be MCRegister
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
HexagonBitSimplify.cpp - Function takes BitTracker::RegisterRef which appears to be unsigned&
MachineVerifier.cpp - Ambiguous operator==() given MCRegister and const Register
PPCFastISel.cpp - No Register::operator-=()
PeepholeOptimizer.cpp - TargetInstrInfo::optimizeLoadInstr() takes an unsigned&
MachineTraceMetrics.cpp - MachineTraceMetrics lacks a suitable constructor
Manual fixups in:
ARMFastISel.cpp - ARMEmitLoad() now takes a Register& instead of unsigned&
HexagonSplitDouble.cpp - Ternary operator was ambiguous between unsigned/Register
HexagonConstExtenders.cpp - Has a local class named Register, used llvm::Register instead of Register.
PPCFastISel.cpp - PPCEmitLoad() now takes a Register& instead of unsigned&
Depends on D65919
Reviewers: arsenm, bogner, craig.topper, RKSimon
Reviewed By: arsenm
Subscribers: RKSimon, craig.topper, lenary, aemerson, wuzish, jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65962
llvm-svn: 369041
2019-08-15 19:22:08 +00:00
|
|
|
Register Reg = MI.getOperand(i).getReg();
|
2019-03-15 21:44:49 +00:00
|
|
|
if (Reg < ARM::R0 || Reg > ARM::R7) {
|
|
|
|
if (!(MI.getOpcode() == ARM::tPUSH && Reg == ARM::LR) &&
|
|
|
|
!(MI.getOpcode() == ARM::tPOP_RET && Reg == ARM::PC)) {
|
|
|
|
ErrInfo = "Unsupported register in Thumb1 push/pop";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-09-21 02:20:46 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-07-25 19:31:34 +00:00
|
|
|
// LoadStackGuard has so far only been implemented for MachO. Different code
|
|
|
|
// sequence is needed for other targets.
|
|
|
|
void ARMBaseInstrInfo::expandLoadStackGuardBase(MachineBasicBlock::iterator MI,
|
|
|
|
unsigned LoadImmOpc,
|
2016-06-28 15:18:26 +00:00
|
|
|
unsigned LoadOpc) const {
|
2016-08-08 15:28:31 +00:00
|
|
|
assert(!Subtarget.isROPI() && !Subtarget.isRWPI() &&
|
|
|
|
"ROPI/RWPI not currently supported with stack guard");
|
|
|
|
|
2014-07-25 19:31:34 +00:00
|
|
|
MachineBasicBlock &MBB = *MI->getParent();
|
|
|
|
DebugLoc DL = MI->getDebugLoc();
|
Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Partial reverts in:
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
X86FixupLEAs.cpp - Some functions return unsigned and arguably should be MCRegister
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
HexagonBitSimplify.cpp - Function takes BitTracker::RegisterRef which appears to be unsigned&
MachineVerifier.cpp - Ambiguous operator==() given MCRegister and const Register
PPCFastISel.cpp - No Register::operator-=()
PeepholeOptimizer.cpp - TargetInstrInfo::optimizeLoadInstr() takes an unsigned&
MachineTraceMetrics.cpp - MachineTraceMetrics lacks a suitable constructor
Manual fixups in:
ARMFastISel.cpp - ARMEmitLoad() now takes a Register& instead of unsigned&
HexagonSplitDouble.cpp - Ternary operator was ambiguous between unsigned/Register
HexagonConstExtenders.cpp - Has a local class named Register, used llvm::Register instead of Register.
PPCFastISel.cpp - PPCEmitLoad() now takes a Register& instead of unsigned&
Depends on D65919
Reviewers: arsenm, bogner, craig.topper, RKSimon
Reviewed By: arsenm
Subscribers: RKSimon, craig.topper, lenary, aemerson, wuzish, jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65962
llvm-svn: 369041
2019-08-15 19:22:08 +00:00
|
|
|
Register Reg = MI->getOperand(0).getReg();
|
2014-07-25 19:31:34 +00:00
|
|
|
const GlobalValue *GV =
|
|
|
|
cast<GlobalValue>((*MI->memoperands_begin())->getValue());
|
|
|
|
MachineInstrBuilder MIB;
|
|
|
|
|
|
|
|
BuildMI(MBB, MI, DL, get(LoadImmOpc), Reg)
|
|
|
|
.addGlobalAddress(GV, 0, ARMII::MO_NONLAZY);
|
|
|
|
|
2016-06-28 15:38:13 +00:00
|
|
|
if (Subtarget.isGVIndirectSymbol(GV)) {
|
2014-07-25 19:31:34 +00:00
|
|
|
MIB = BuildMI(MBB, MI, DL, get(LoadOpc), Reg);
|
|
|
|
MIB.addReg(Reg, RegState::Kill).addImm(0);
|
[CodeGen] Split out the notions of MI invariance and MI dereferenceability.
Summary:
An IR load can be invariant, dereferenceable, neither, or both. But
currently, MI's notion of invariance is IR-invariant &&
IR-dereferenceable.
This patch splits up the notions of invariance and dereferenceability at
the MI level. It's NFC, so adds some probably-unnecessary
"is-dereferenceable" checks, which we can remove later if desired.
Reviewers: chandlerc, tstellarAMD
Subscribers: jholewinski, arsenm, nemanjai, llvm-commits
Differential Revision: https://reviews.llvm.org/D23371
llvm-svn: 281151
2016-09-11 01:38:58 +00:00
|
|
|
auto Flags = MachineMemOperand::MOLoad |
|
|
|
|
MachineMemOperand::MODereferenceable |
|
|
|
|
MachineMemOperand::MOInvariant;
|
2015-08-11 23:09:45 +00:00
|
|
|
MachineMemOperand *MMO = MBB.getParent()->getMachineMemOperand(
|
2020-03-31 09:43:50 +00:00
|
|
|
MachinePointerInfo::getGOT(*MBB.getParent()), Flags, 4, Align(4));
|
2017-01-13 09:37:56 +00:00
|
|
|
MIB.addMemOperand(MMO).add(predOps(ARMCC::AL));
|
2014-07-25 19:31:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
MIB = BuildMI(MBB, MI, DL, get(LoadOpc), Reg);
|
2017-01-13 09:37:56 +00:00
|
|
|
MIB.addReg(Reg, RegState::Kill)
|
2018-08-16 21:30:05 +00:00
|
|
|
.addImm(0)
|
|
|
|
.cloneMemRefs(*MI)
|
|
|
|
.add(predOps(ARMCC::AL));
|
2014-07-25 19:31:34 +00:00
|
|
|
}
|
|
|
|
|
2010-12-05 22:04:16 +00:00
|
|
|
bool
|
|
|
|
ARMBaseInstrInfo::isFpMLxInstruction(unsigned Opcode, unsigned &MulOpc,
|
|
|
|
unsigned &AddSubOpc,
|
|
|
|
bool &NegAcc, bool &HasLane) const {
|
|
|
|
DenseMap<unsigned, unsigned>::const_iterator I = MLxEntryMap.find(Opcode);
|
|
|
|
if (I == MLxEntryMap.end())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
const ARM_MLxEntry &Entry = ARM_MLxTable[I->second];
|
|
|
|
MulOpc = Entry.MulOpc;
|
|
|
|
AddSubOpc = Entry.AddSubOpc;
|
|
|
|
NegAcc = Entry.NegAcc;
|
|
|
|
HasLane = Entry.HasLane;
|
|
|
|
return true;
|
|
|
|
}
|
2011-09-27 22:57:21 +00:00
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Execution domains.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// Some instructions go down the NEON pipeline, some go down the VFP pipeline,
|
|
|
|
// and some can go down both. The vmov instructions go down the VFP pipeline,
|
|
|
|
// but they can be changed to vorr equivalents that are executed by the NEON
|
|
|
|
// pipeline.
|
|
|
|
//
|
|
|
|
// We use the following execution domain numbering:
|
|
|
|
//
|
2011-09-29 02:48:41 +00:00
|
|
|
enum ARMExeDomain {
|
|
|
|
ExeGeneric = 0,
|
|
|
|
ExeVFP = 1,
|
|
|
|
ExeNEON = 2
|
|
|
|
};
|
2017-01-26 23:40:06 +00:00
|
|
|
|
2011-09-27 22:57:21 +00:00
|
|
|
//
|
|
|
|
// Also see ARMInstrFormats.td and Domain* enums in ARMBaseInfo.h
|
|
|
|
//
|
|
|
|
std::pair<uint16_t, uint16_t>
|
2016-06-30 00:01:54 +00:00
|
|
|
ARMBaseInstrInfo::getExecutionDomain(const MachineInstr &MI) const {
|
2015-03-07 00:12:22 +00:00
|
|
|
// If we don't have access to NEON instructions then we won't be able
|
|
|
|
// to swizzle anything to the NEON domain. Check to make sure.
|
|
|
|
if (Subtarget.hasNEON()) {
|
|
|
|
// VMOVD, VMOVRS and VMOVSR are VFP instructions, but can be changed to NEON
|
|
|
|
// if they are not predicated.
|
2016-06-30 00:01:54 +00:00
|
|
|
if (MI.getOpcode() == ARM::VMOVD && !isPredicated(MI))
|
2015-03-07 00:12:22 +00:00
|
|
|
return std::make_pair(ExeVFP, (1 << ExeVFP) | (1 << ExeNEON));
|
|
|
|
|
|
|
|
// CortexA9 is particularly picky about mixing the two and wants these
|
|
|
|
// converted.
|
2016-06-30 00:01:54 +00:00
|
|
|
if (Subtarget.useNEONForFPMovs() && !isPredicated(MI) &&
|
|
|
|
(MI.getOpcode() == ARM::VMOVRS || MI.getOpcode() == ARM::VMOVSR ||
|
|
|
|
MI.getOpcode() == ARM::VMOVS))
|
2015-03-07 00:12:22 +00:00
|
|
|
return std::make_pair(ExeVFP, (1 << ExeVFP) | (1 << ExeNEON));
|
|
|
|
}
|
2011-09-27 22:57:21 +00:00
|
|
|
// No other instructions can be swizzled, so just determine their domain.
|
2016-06-30 00:01:54 +00:00
|
|
|
unsigned Domain = MI.getDesc().TSFlags & ARMII::DomainMask;
|
2011-09-27 22:57:21 +00:00
|
|
|
|
|
|
|
if (Domain & ARMII::DomainNEON)
|
2011-09-29 02:48:41 +00:00
|
|
|
return std::make_pair(ExeNEON, 0);
|
2011-09-27 22:57:21 +00:00
|
|
|
|
|
|
|
// Certain instructions can go either way on Cortex-A8.
|
|
|
|
// Treat them as NEON instructions.
|
|
|
|
if ((Domain & ARMII::DomainNEONA8) && Subtarget.isCortexA8())
|
2011-09-29 02:48:41 +00:00
|
|
|
return std::make_pair(ExeNEON, 0);
|
2011-09-27 22:57:21 +00:00
|
|
|
|
|
|
|
if (Domain & ARMII::DomainVFP)
|
2011-09-29 02:48:41 +00:00
|
|
|
return std::make_pair(ExeVFP, 0);
|
2011-09-27 22:57:21 +00:00
|
|
|
|
2011-09-29 02:48:41 +00:00
|
|
|
return std::make_pair(ExeGeneric, 0);
|
2011-09-27 22:57:21 +00:00
|
|
|
}
|
|
|
|
|
2012-08-29 16:36:07 +00:00
|
|
|
static unsigned getCorrespondingDRegAndLane(const TargetRegisterInfo *TRI,
|
|
|
|
unsigned SReg, unsigned &Lane) {
|
|
|
|
unsigned DReg = TRI->getMatchingSuperReg(SReg, ARM::ssub_0, &ARM::DPRRegClass);
|
|
|
|
Lane = 0;
|
|
|
|
|
|
|
|
if (DReg != ARM::NoRegister)
|
|
|
|
return DReg;
|
|
|
|
|
|
|
|
Lane = 1;
|
|
|
|
DReg = TRI->getMatchingSuperReg(SReg, ARM::ssub_1, &ARM::DPRRegClass);
|
|
|
|
|
|
|
|
assert(DReg && "S-register with no D super-register?");
|
|
|
|
return DReg;
|
|
|
|
}
|
|
|
|
|
2012-10-10 05:43:01 +00:00
|
|
|
/// getImplicitSPRUseForDPRUse - Given a use of a DPR register and lane,
|
2012-09-18 08:31:15 +00:00
|
|
|
/// set ImplicitSReg to a register number that must be marked as implicit-use or
|
|
|
|
/// zero if no register needs to be defined as implicit-use.
|
|
|
|
///
|
|
|
|
/// If the function cannot determine if an SPR should be marked implicit use or
|
|
|
|
/// not, it returns false.
|
|
|
|
///
|
|
|
|
/// This function handles cases where an instruction is being modified from taking
|
2012-10-10 05:43:01 +00:00
|
|
|
/// an SPR to a DPR[Lane]. A use of the DPR is being added, which may conflict
|
2012-09-18 08:31:15 +00:00
|
|
|
/// with an earlier def of an SPR corresponding to DPR[Lane^1] (i.e. the other
|
|
|
|
/// lane of the DPR).
|
|
|
|
///
|
|
|
|
/// If the other SPR is defined, an implicit-use of it should be added. Else,
|
|
|
|
/// (including the case where the DPR itself is defined), it should not.
|
2012-10-10 05:43:01 +00:00
|
|
|
///
|
2012-09-18 08:31:15 +00:00
|
|
|
static bool getImplicitSPRUseForDPRUse(const TargetRegisterInfo *TRI,
|
2016-06-30 00:01:54 +00:00
|
|
|
MachineInstr &MI, unsigned DReg,
|
|
|
|
unsigned Lane, unsigned &ImplicitSReg) {
|
2012-09-18 08:31:15 +00:00
|
|
|
// If the DPR is defined or used already, the other SPR lane will be chained
|
|
|
|
// correctly, so there is nothing to be done.
|
2016-06-30 00:01:54 +00:00
|
|
|
if (MI.definesRegister(DReg, TRI) || MI.readsRegister(DReg, TRI)) {
|
2012-09-18 08:31:15 +00:00
|
|
|
ImplicitSReg = 0;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise we need to go searching to see if the SPR is set explicitly.
|
|
|
|
ImplicitSReg = TRI->getSubReg(DReg,
|
|
|
|
(Lane & 1) ? ARM::ssub_0 : ARM::ssub_1);
|
|
|
|
MachineBasicBlock::LivenessQueryResult LQR =
|
2016-06-30 00:01:54 +00:00
|
|
|
MI.getParent()->computeRegisterLiveness(TRI, ImplicitSReg, MI);
|
2012-09-18 08:31:15 +00:00
|
|
|
|
|
|
|
if (LQR == MachineBasicBlock::LQR_Live)
|
|
|
|
return true;
|
|
|
|
else if (LQR == MachineBasicBlock::LQR_Unknown)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// If the register is known not to be live, there is no need to add an
|
|
|
|
// implicit-use.
|
|
|
|
ImplicitSReg = 0;
|
|
|
|
return true;
|
|
|
|
}
|
2012-08-29 16:36:07 +00:00
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
void ARMBaseInstrInfo::setExecutionDomain(MachineInstr &MI,
|
|
|
|
unsigned Domain) const {
|
2012-08-17 11:32:52 +00:00
|
|
|
unsigned DstReg, SrcReg, DReg;
|
|
|
|
unsigned Lane;
|
2016-06-30 00:01:54 +00:00
|
|
|
MachineInstrBuilder MIB(*MI.getParent()->getParent(), MI);
|
2012-08-17 11:32:52 +00:00
|
|
|
const TargetRegisterInfo *TRI = &getRegisterInfo();
|
2016-06-30 00:01:54 +00:00
|
|
|
switch (MI.getOpcode()) {
|
|
|
|
default:
|
|
|
|
llvm_unreachable("cannot handle opcode!");
|
|
|
|
break;
|
|
|
|
case ARM::VMOVD:
|
|
|
|
if (Domain != ExeNEON)
|
2012-08-17 11:32:52 +00:00
|
|
|
break;
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
// Zap the predicate operands.
|
|
|
|
assert(!isPredicated(MI) && "Cannot predicate a VORRd");
|
2012-08-17 11:32:52 +00:00
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
// Make sure we've got NEON instructions.
|
|
|
|
assert(Subtarget.hasNEON() && "VORRd requires NEON");
|
2015-03-07 00:12:22 +00:00
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
// Source instruction is %DDst = VMOVD %DSrc, 14, %noreg (; implicits)
|
|
|
|
DstReg = MI.getOperand(0).getReg();
|
|
|
|
SrcReg = MI.getOperand(1).getReg();
|
2012-08-17 11:32:52 +00:00
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
for (unsigned i = MI.getDesc().getNumOperands(); i; --i)
|
|
|
|
MI.RemoveOperand(i - 1);
|
2012-08-29 16:36:07 +00:00
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
// Change to a %DDst = VORRd %DSrc, %DSrc, 14, %noreg (; implicits)
|
|
|
|
MI.setDesc(get(ARM::VORRd));
|
2017-01-13 09:37:56 +00:00
|
|
|
MIB.addReg(DstReg, RegState::Define)
|
|
|
|
.addReg(SrcReg)
|
|
|
|
.addReg(SrcReg)
|
|
|
|
.add(predOps(ARMCC::AL));
|
2016-06-30 00:01:54 +00:00
|
|
|
break;
|
|
|
|
case ARM::VMOVRS:
|
|
|
|
if (Domain != ExeNEON)
|
2012-08-17 11:32:52 +00:00
|
|
|
break;
|
2016-06-30 00:01:54 +00:00
|
|
|
assert(!isPredicated(MI) && "Cannot predicate a VGETLN");
|
2012-08-17 11:32:52 +00:00
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
// Source instruction is %RDst = VMOVRS %SSrc, 14, %noreg (; implicits)
|
|
|
|
DstReg = MI.getOperand(0).getReg();
|
|
|
|
SrcReg = MI.getOperand(1).getReg();
|
2011-09-27 22:57:21 +00:00
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
for (unsigned i = MI.getDesc().getNumOperands(); i; --i)
|
|
|
|
MI.RemoveOperand(i - 1);
|
2012-08-17 11:32:52 +00:00
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
DReg = getCorrespondingDRegAndLane(TRI, SrcReg, Lane);
|
2012-08-17 11:32:52 +00:00
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
// Convert to %RDst = VGETLNi32 %DSrc, Lane, 14, %noreg (; imps)
|
|
|
|
// Note that DSrc has been widened and the other lane may be undef, which
|
|
|
|
// contaminates the entire register.
|
|
|
|
MI.setDesc(get(ARM::VGETLNi32));
|
2017-01-13 09:37:56 +00:00
|
|
|
MIB.addReg(DstReg, RegState::Define)
|
|
|
|
.addReg(DReg, RegState::Undef)
|
|
|
|
.addImm(Lane)
|
|
|
|
.add(predOps(ARMCC::AL));
|
2012-08-17 11:32:52 +00:00
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
// The old source should be an implicit use, otherwise we might think it
|
|
|
|
// was dead before here.
|
|
|
|
MIB.addReg(SrcReg, RegState::Implicit);
|
|
|
|
break;
|
|
|
|
case ARM::VMOVSR: {
|
|
|
|
if (Domain != ExeNEON)
|
2012-08-17 11:32:52 +00:00
|
|
|
break;
|
2016-06-30 00:01:54 +00:00
|
|
|
assert(!isPredicated(MI) && "Cannot predicate a VSETLN");
|
2012-08-17 11:32:52 +00:00
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
// Source instruction is %SDst = VMOVSR %RSrc, 14, %noreg (; implicits)
|
|
|
|
DstReg = MI.getOperand(0).getReg();
|
|
|
|
SrcReg = MI.getOperand(1).getReg();
|
2012-08-17 11:32:52 +00:00
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
DReg = getCorrespondingDRegAndLane(TRI, DstReg, Lane);
|
2012-08-17 11:32:52 +00:00
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
unsigned ImplicitSReg;
|
|
|
|
if (!getImplicitSPRUseForDPRUse(TRI, MI, DReg, Lane, ImplicitSReg))
|
|
|
|
break;
|
2012-09-01 18:07:29 +00:00
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
for (unsigned i = MI.getDesc().getNumOperands(); i; --i)
|
|
|
|
MI.RemoveOperand(i - 1);
|
2012-09-05 18:37:53 +00:00
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
// Convert to %DDst = VSETLNi32 %DDst, %RSrc, Lane, 14, %noreg (; imps)
|
|
|
|
// Again DDst may be undefined at the beginning of this instruction.
|
|
|
|
MI.setDesc(get(ARM::VSETLNi32));
|
|
|
|
MIB.addReg(DReg, RegState::Define)
|
|
|
|
.addReg(DReg, getUndefRegState(!MI.readsRegister(DReg, TRI)))
|
|
|
|
.addReg(SrcReg)
|
2017-01-13 09:37:56 +00:00
|
|
|
.addImm(Lane)
|
|
|
|
.add(predOps(ARMCC::AL));
|
2012-08-30 10:17:45 +00:00
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
// The narrower destination must be marked as set to keep previous chains
|
|
|
|
// in place.
|
|
|
|
MIB.addReg(DstReg, RegState::Define | RegState::Implicit);
|
|
|
|
if (ImplicitSReg != 0)
|
|
|
|
MIB.addReg(ImplicitSReg, RegState::Implicit);
|
|
|
|
break;
|
2012-09-18 08:31:15 +00:00
|
|
|
}
|
2012-08-30 10:17:45 +00:00
|
|
|
case ARM::VMOVS: {
|
|
|
|
if (Domain != ExeNEON)
|
|
|
|
break;
|
|
|
|
|
|
|
|
// Source instruction is %SDst = VMOVS %SSrc, 14, %noreg (; implicits)
|
2016-06-30 00:01:54 +00:00
|
|
|
DstReg = MI.getOperand(0).getReg();
|
|
|
|
SrcReg = MI.getOperand(1).getReg();
|
2012-08-30 10:17:45 +00:00
|
|
|
|
|
|
|
unsigned DstLane = 0, SrcLane = 0, DDst, DSrc;
|
|
|
|
DDst = getCorrespondingDRegAndLane(TRI, DstReg, DstLane);
|
|
|
|
DSrc = getCorrespondingDRegAndLane(TRI, SrcReg, SrcLane);
|
|
|
|
|
2012-09-18 08:31:15 +00:00
|
|
|
unsigned ImplicitSReg;
|
|
|
|
if (!getImplicitSPRUseForDPRUse(TRI, MI, DSrc, SrcLane, ImplicitSReg))
|
|
|
|
break;
|
2012-09-01 18:07:29 +00:00
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
for (unsigned i = MI.getDesc().getNumOperands(); i; --i)
|
|
|
|
MI.RemoveOperand(i - 1);
|
2012-09-05 18:37:53 +00:00
|
|
|
|
2012-08-30 10:17:45 +00:00
|
|
|
if (DSrc == DDst) {
|
|
|
|
// Destination can be:
|
|
|
|
// %DDst = VDUPLN32d %DDst, Lane, 14, %noreg (; implicits)
|
2016-06-30 00:01:54 +00:00
|
|
|
MI.setDesc(get(ARM::VDUPLN32d));
|
2012-09-01 18:07:29 +00:00
|
|
|
MIB.addReg(DDst, RegState::Define)
|
2016-06-30 00:01:54 +00:00
|
|
|
.addReg(DDst, getUndefRegState(!MI.readsRegister(DDst, TRI)))
|
2017-01-13 09:37:56 +00:00
|
|
|
.addImm(SrcLane)
|
|
|
|
.add(predOps(ARMCC::AL));
|
2012-08-30 10:17:45 +00:00
|
|
|
|
|
|
|
// Neither the source or the destination are naturally represented any
|
|
|
|
// more, so add them in manually.
|
|
|
|
MIB.addReg(DstReg, RegState::Implicit | RegState::Define);
|
|
|
|
MIB.addReg(SrcReg, RegState::Implicit);
|
2012-09-18 08:31:15 +00:00
|
|
|
if (ImplicitSReg != 0)
|
|
|
|
MIB.addReg(ImplicitSReg, RegState::Implicit);
|
2012-08-30 10:17:45 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// In general there's no single instruction that can perform an S <-> S
|
|
|
|
// move in NEON space, but a pair of VEXT instructions *can* do the
|
|
|
|
// job. It turns out that the VEXTs needed will only use DSrc once, with
|
|
|
|
// the position based purely on the combination of lane-0 and lane-1
|
|
|
|
// involved. For example
|
|
|
|
// vmov s0, s2 -> vext.32 d0, d0, d1, #1 vext.32 d0, d0, d0, #1
|
|
|
|
// vmov s1, s3 -> vext.32 d0, d1, d0, #1 vext.32 d0, d0, d0, #1
|
|
|
|
// vmov s0, s3 -> vext.32 d0, d0, d0, #1 vext.32 d0, d1, d0, #1
|
|
|
|
// vmov s1, s2 -> vext.32 d0, d0, d0, #1 vext.32 d0, d0, d1, #1
|
|
|
|
//
|
|
|
|
// Pattern of the MachineInstrs is:
|
|
|
|
// %DDst = VEXTd32 %DSrc1, %DSrc2, Lane, 14, %noreg (;implicits)
|
|
|
|
MachineInstrBuilder NewMIB;
|
2016-06-30 00:01:54 +00:00
|
|
|
NewMIB = BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), get(ARM::VEXTd32),
|
|
|
|
DDst);
|
2012-09-01 18:07:29 +00:00
|
|
|
|
2017-12-07 10:40:31 +00:00
|
|
|
// On the first instruction, both DSrc and DDst may be undef if present.
|
2012-09-01 18:07:29 +00:00
|
|
|
// Specifically when the original instruction didn't have them as an
|
|
|
|
// <imp-use>.
|
|
|
|
unsigned CurReg = SrcLane == 1 && DstLane == 1 ? DSrc : DDst;
|
2016-06-30 00:01:54 +00:00
|
|
|
bool CurUndef = !MI.readsRegister(CurReg, TRI);
|
2012-09-01 18:07:29 +00:00
|
|
|
NewMIB.addReg(CurReg, getUndefRegState(CurUndef));
|
|
|
|
|
|
|
|
CurReg = SrcLane == 0 && DstLane == 0 ? DSrc : DDst;
|
2016-06-30 00:01:54 +00:00
|
|
|
CurUndef = !MI.readsRegister(CurReg, TRI);
|
2017-01-13 09:37:56 +00:00
|
|
|
NewMIB.addReg(CurReg, getUndefRegState(CurUndef))
|
|
|
|
.addImm(1)
|
|
|
|
.add(predOps(ARMCC::AL));
|
2012-08-30 10:17:45 +00:00
|
|
|
|
|
|
|
if (SrcLane == DstLane)
|
|
|
|
NewMIB.addReg(SrcReg, RegState::Implicit);
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
MI.setDesc(get(ARM::VEXTd32));
|
2012-08-30 10:17:45 +00:00
|
|
|
MIB.addReg(DDst, RegState::Define);
|
2012-09-01 18:07:29 +00:00
|
|
|
|
|
|
|
// On the second instruction, DDst has definitely been defined above, so
|
2017-12-07 10:40:31 +00:00
|
|
|
// it is not undef. DSrc, if present, can be undef as above.
|
2012-09-01 18:07:29 +00:00
|
|
|
CurReg = SrcLane == 1 && DstLane == 0 ? DSrc : DDst;
|
2016-06-30 00:01:54 +00:00
|
|
|
CurUndef = CurReg == DSrc && !MI.readsRegister(CurReg, TRI);
|
2012-09-01 18:07:29 +00:00
|
|
|
MIB.addReg(CurReg, getUndefRegState(CurUndef));
|
|
|
|
|
|
|
|
CurReg = SrcLane == 0 && DstLane == 1 ? DSrc : DDst;
|
2016-06-30 00:01:54 +00:00
|
|
|
CurUndef = CurReg == DSrc && !MI.readsRegister(CurReg, TRI);
|
2017-01-13 09:37:56 +00:00
|
|
|
MIB.addReg(CurReg, getUndefRegState(CurUndef))
|
|
|
|
.addImm(1)
|
|
|
|
.add(predOps(ARMCC::AL));
|
2012-08-30 10:17:45 +00:00
|
|
|
|
|
|
|
if (SrcLane != DstLane)
|
|
|
|
MIB.addReg(SrcReg, RegState::Implicit);
|
|
|
|
|
|
|
|
// As before, the original destination is no longer represented, add it
|
|
|
|
// implicitly.
|
|
|
|
MIB.addReg(DstReg, RegState::Define | RegState::Implicit);
|
2012-09-18 08:31:15 +00:00
|
|
|
if (ImplicitSReg != 0)
|
|
|
|
MIB.addReg(ImplicitSReg, RegState::Implicit);
|
2012-08-30 10:17:45 +00:00
|
|
|
break;
|
|
|
|
}
|
2012-08-17 11:32:52 +00:00
|
|
|
}
|
2011-09-27 22:57:21 +00:00
|
|
|
}
|
2012-02-28 23:53:30 +00:00
|
|
|
|
2012-09-29 21:43:49 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Partial register updates
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// Swift renames NEON registers with 64-bit granularity. That means any
|
|
|
|
// instruction writing an S-reg implicitly reads the containing D-reg. The
|
|
|
|
// problem is mostly avoided by translating f32 operations to v2f32 operations
|
|
|
|
// on D-registers, but f32 loads are still a problem.
|
|
|
|
//
|
|
|
|
// These instructions can load an f32 into a NEON register:
|
|
|
|
//
|
|
|
|
// VLDRS - Only writes S, partial D update.
|
|
|
|
// VLD1LNd32 - Writes all D-regs, explicit partial D update, 2 uops.
|
|
|
|
// VLD1DUPd32 - Writes all D-regs, no partial reg update, 2 uops.
|
|
|
|
//
|
|
|
|
// FCONSTD can be used as a dependency-breaking instruction.
|
2016-06-30 00:01:54 +00:00
|
|
|
unsigned ARMBaseInstrInfo::getPartialRegUpdateClearance(
|
|
|
|
const MachineInstr &MI, unsigned OpNum,
|
|
|
|
const TargetRegisterInfo *TRI) const {
|
2016-07-06 11:22:11 +00:00
|
|
|
auto PartialUpdateClearance = Subtarget.getPartialUpdateClearance();
|
|
|
|
if (!PartialUpdateClearance)
|
2012-09-29 21:43:49 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
assert(TRI && "Need TRI instance");
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
const MachineOperand &MO = MI.getOperand(OpNum);
|
2012-09-29 21:43:49 +00:00
|
|
|
if (MO.readsReg())
|
|
|
|
return 0;
|
Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Partial reverts in:
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
X86FixupLEAs.cpp - Some functions return unsigned and arguably should be MCRegister
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
HexagonBitSimplify.cpp - Function takes BitTracker::RegisterRef which appears to be unsigned&
MachineVerifier.cpp - Ambiguous operator==() given MCRegister and const Register
PPCFastISel.cpp - No Register::operator-=()
PeepholeOptimizer.cpp - TargetInstrInfo::optimizeLoadInstr() takes an unsigned&
MachineTraceMetrics.cpp - MachineTraceMetrics lacks a suitable constructor
Manual fixups in:
ARMFastISel.cpp - ARMEmitLoad() now takes a Register& instead of unsigned&
HexagonSplitDouble.cpp - Ternary operator was ambiguous between unsigned/Register
HexagonConstExtenders.cpp - Has a local class named Register, used llvm::Register instead of Register.
PPCFastISel.cpp - PPCEmitLoad() now takes a Register& instead of unsigned&
Depends on D65919
Reviewers: arsenm, bogner, craig.topper, RKSimon
Reviewed By: arsenm
Subscribers: RKSimon, craig.topper, lenary, aemerson, wuzish, jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65962
llvm-svn: 369041
2019-08-15 19:22:08 +00:00
|
|
|
Register Reg = MO.getReg();
|
2012-09-29 21:43:49 +00:00
|
|
|
int UseOp = -1;
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
switch (MI.getOpcode()) {
|
|
|
|
// Normal instructions writing only an S-register.
|
2012-09-29 21:43:49 +00:00
|
|
|
case ARM::VLDRS:
|
|
|
|
case ARM::FCONSTS:
|
|
|
|
case ARM::VMOVSR:
|
|
|
|
case ARM::VMOVv8i8:
|
|
|
|
case ARM::VMOVv4i16:
|
|
|
|
case ARM::VMOVv2i32:
|
|
|
|
case ARM::VMOVv2f32:
|
|
|
|
case ARM::VMOVv1i64:
|
2016-06-30 00:01:54 +00:00
|
|
|
UseOp = MI.findRegisterUseOperandIdx(Reg, false, TRI);
|
2012-09-29 21:43:49 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
// Explicitly reads the dependency.
|
|
|
|
case ARM::VLD1LNd32:
|
2013-03-27 12:38:44 +00:00
|
|
|
UseOp = 3;
|
2012-09-29 21:43:49 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If this instruction actually reads a value from Reg, there is no unwanted
|
|
|
|
// dependency.
|
2016-06-30 00:01:54 +00:00
|
|
|
if (UseOp != -1 && MI.getOperand(UseOp).readsReg())
|
2012-09-29 21:43:49 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
// We must be able to clobber the whole D-reg.
|
2019-08-01 23:27:28 +00:00
|
|
|
if (Register::isVirtualRegister(Reg)) {
|
2017-12-07 10:40:31 +00:00
|
|
|
// Virtual register must be a def undef foo:ssub_0 operand.
|
2016-06-30 00:01:54 +00:00
|
|
|
if (!MO.getSubReg() || MI.readsVirtualRegister(Reg))
|
2012-09-29 21:43:49 +00:00
|
|
|
return 0;
|
|
|
|
} else if (ARM::SPRRegClass.contains(Reg)) {
|
|
|
|
// Physical register: MI must define the full D-reg.
|
|
|
|
unsigned DReg = TRI->getMatchingSuperReg(Reg, ARM::ssub_0,
|
|
|
|
&ARM::DPRRegClass);
|
2016-06-30 00:01:54 +00:00
|
|
|
if (!DReg || !MI.definesRegister(DReg, TRI))
|
2012-09-29 21:43:49 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// MI has an unwanted D-register dependency.
|
|
|
|
// Avoid defs in the previous N instructrions.
|
2016-07-06 11:22:11 +00:00
|
|
|
return PartialUpdateClearance;
|
2012-09-29 21:43:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Break a partial register dependency after getPartialRegUpdateClearance
|
|
|
|
// returned non-zero.
|
2016-06-30 00:01:54 +00:00
|
|
|
void ARMBaseInstrInfo::breakPartialRegDependency(
|
|
|
|
MachineInstr &MI, unsigned OpNum, const TargetRegisterInfo *TRI) const {
|
|
|
|
assert(OpNum < MI.getDesc().getNumDefs() && "OpNum is not a def");
|
2012-09-29 21:43:49 +00:00
|
|
|
assert(TRI && "Need TRI instance");
|
|
|
|
|
2016-06-30 00:01:54 +00:00
|
|
|
const MachineOperand &MO = MI.getOperand(OpNum);
|
Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Partial reverts in:
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
X86FixupLEAs.cpp - Some functions return unsigned and arguably should be MCRegister
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
HexagonBitSimplify.cpp - Function takes BitTracker::RegisterRef which appears to be unsigned&
MachineVerifier.cpp - Ambiguous operator==() given MCRegister and const Register
PPCFastISel.cpp - No Register::operator-=()
PeepholeOptimizer.cpp - TargetInstrInfo::optimizeLoadInstr() takes an unsigned&
MachineTraceMetrics.cpp - MachineTraceMetrics lacks a suitable constructor
Manual fixups in:
ARMFastISel.cpp - ARMEmitLoad() now takes a Register& instead of unsigned&
HexagonSplitDouble.cpp - Ternary operator was ambiguous between unsigned/Register
HexagonConstExtenders.cpp - Has a local class named Register, used llvm::Register instead of Register.
PPCFastISel.cpp - PPCEmitLoad() now takes a Register& instead of unsigned&
Depends on D65919
Reviewers: arsenm, bogner, craig.topper, RKSimon
Reviewed By: arsenm
Subscribers: RKSimon, craig.topper, lenary, aemerson, wuzish, jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65962
llvm-svn: 369041
2019-08-15 19:22:08 +00:00
|
|
|
Register Reg = MO.getReg();
|
2019-08-01 23:27:28 +00:00
|
|
|
assert(Register::isPhysicalRegister(Reg) &&
|
2012-09-29 21:43:49 +00:00
|
|
|
"Can't break virtual register dependencies.");
|
|
|
|
unsigned DReg = Reg;
|
|
|
|
|
|
|
|
// If MI defines an S-reg, find the corresponding D super-register.
|
|
|
|
if (ARM::SPRRegClass.contains(Reg)) {
|
|
|
|
DReg = ARM::D0 + (Reg - ARM::S0) / 2;
|
|
|
|
assert(TRI->isSuperRegister(Reg, DReg) && "Register enums broken");
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(ARM::DPRRegClass.contains(DReg) && "Can only break D-reg deps");
|
2016-06-30 00:01:54 +00:00
|
|
|
assert(MI.definesRegister(DReg, TRI) && "MI doesn't clobber full D-reg");
|
2012-09-29 21:43:49 +00:00
|
|
|
|
|
|
|
// FIXME: In some cases, VLDRS can be changed to a VLD1DUPd32 which defines
|
|
|
|
// the full D-register by loading the same value to both lanes. The
|
|
|
|
// instruction is micro-coded with 2 uops, so don't do this until we can
|
2013-09-14 09:34:24 +00:00
|
|
|
// properly schedule micro-coded instructions. The dispatcher stalls cause
|
2012-09-29 21:43:49 +00:00
|
|
|
// too big regressions.
|
|
|
|
|
|
|
|
// Insert the dependency-breaking FCONSTD before MI.
|
|
|
|
// 96 is the encoding of 0.5, but the actual value doesn't matter here.
|
2017-01-13 09:37:56 +00:00
|
|
|
BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), get(ARM::FCONSTD), DReg)
|
|
|
|
.addImm(96)
|
|
|
|
.add(predOps(ARMCC::AL));
|
2016-06-30 00:01:54 +00:00
|
|
|
MI.addRegisterKilled(DReg, TRI, true);
|
2012-09-29 21:43:49 +00:00
|
|
|
}
|
|
|
|
|
2012-02-28 23:53:30 +00:00
|
|
|
bool ARMBaseInstrInfo::hasNOP() const {
|
2015-05-26 10:47:10 +00:00
|
|
|
return Subtarget.getFeatureBits()[ARM::HasV6KOps];
|
2012-02-28 23:53:30 +00:00
|
|
|
}
|
2013-04-05 04:42:00 +00:00
|
|
|
|
|
|
|
bool ARMBaseInstrInfo::isSwiftFastImmShift(const MachineInstr *MI) const {
|
2013-06-05 14:59:36 +00:00
|
|
|
if (MI->getNumOperands() < 4)
|
|
|
|
return true;
|
2013-04-05 04:42:00 +00:00
|
|
|
unsigned ShOpVal = MI->getOperand(3).getImm();
|
|
|
|
unsigned ShImm = ARM_AM::getSORegOffset(ShOpVal);
|
|
|
|
// Swift supports faster shifts for: lsl 2, lsl 1, and lsr 1.
|
|
|
|
if ((ShImm == 1 && ARM_AM::getSORegShOp(ShOpVal) == ARM_AM::lsr) ||
|
|
|
|
((ShImm == 1 || ShImm == 2) &&
|
|
|
|
ARM_AM::getSORegShOp(ShOpVal) == ARM_AM::lsl))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2014-08-22 18:05:22 +00:00
|
|
|
|
|
|
|
bool ARMBaseInstrInfo::getRegSequenceLikeInputs(
|
|
|
|
const MachineInstr &MI, unsigned DefIdx,
|
|
|
|
SmallVectorImpl<RegSubRegPairAndIdx> &InputRegs) const {
|
|
|
|
assert(DefIdx < MI.getDesc().getNumDefs() && "Invalid definition index");
|
|
|
|
assert(MI.isRegSequenceLike() && "Invalid kind of instruction");
|
|
|
|
|
|
|
|
switch (MI.getOpcode()) {
|
|
|
|
case ARM::VMOVDRR:
|
|
|
|
// dX = VMOVDRR rY, rZ
|
|
|
|
// is the same as:
|
|
|
|
// dX = REG_SEQUENCE rY, ssub_0, rZ, ssub_1
|
|
|
|
// Populate the InputRegs accordingly.
|
|
|
|
// rY
|
|
|
|
const MachineOperand *MOReg = &MI.getOperand(1);
|
2018-01-11 22:30:43 +00:00
|
|
|
if (!MOReg->isUndef())
|
|
|
|
InputRegs.push_back(RegSubRegPairAndIdx(MOReg->getReg(),
|
|
|
|
MOReg->getSubReg(), ARM::ssub_0));
|
2014-08-22 18:05:22 +00:00
|
|
|
// rZ
|
|
|
|
MOReg = &MI.getOperand(2);
|
2018-01-11 22:30:43 +00:00
|
|
|
if (!MOReg->isUndef())
|
|
|
|
InputRegs.push_back(RegSubRegPairAndIdx(MOReg->getReg(),
|
|
|
|
MOReg->getSubReg(), ARM::ssub_1));
|
2014-08-22 18:05:22 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
llvm_unreachable("Target dependent opcode missing");
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ARMBaseInstrInfo::getExtractSubregLikeInputs(
|
|
|
|
const MachineInstr &MI, unsigned DefIdx,
|
|
|
|
RegSubRegPairAndIdx &InputReg) const {
|
|
|
|
assert(DefIdx < MI.getDesc().getNumDefs() && "Invalid definition index");
|
|
|
|
assert(MI.isExtractSubregLike() && "Invalid kind of instruction");
|
|
|
|
|
|
|
|
switch (MI.getOpcode()) {
|
|
|
|
case ARM::VMOVRRD:
|
|
|
|
// rX, rY = VMOVRRD dZ
|
|
|
|
// is the same as:
|
|
|
|
// rX = EXTRACT_SUBREG dZ, ssub_0
|
|
|
|
// rY = EXTRACT_SUBREG dZ, ssub_1
|
|
|
|
const MachineOperand &MOReg = MI.getOperand(2);
|
2018-01-11 22:30:43 +00:00
|
|
|
if (MOReg.isUndef())
|
|
|
|
return false;
|
2014-08-22 18:05:22 +00:00
|
|
|
InputReg.Reg = MOReg.getReg();
|
|
|
|
InputReg.SubReg = MOReg.getSubReg();
|
|
|
|
InputReg.SubIdx = DefIdx == 0 ? ARM::ssub_0 : ARM::ssub_1;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
llvm_unreachable("Target dependent opcode missing");
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ARMBaseInstrInfo::getInsertSubregLikeInputs(
|
|
|
|
const MachineInstr &MI, unsigned DefIdx, RegSubRegPair &BaseReg,
|
|
|
|
RegSubRegPairAndIdx &InsertedReg) const {
|
|
|
|
assert(DefIdx < MI.getDesc().getNumDefs() && "Invalid definition index");
|
|
|
|
assert(MI.isInsertSubregLike() && "Invalid kind of instruction");
|
|
|
|
|
|
|
|
switch (MI.getOpcode()) {
|
|
|
|
case ARM::VSETLNi32:
|
|
|
|
// dX = VSETLNi32 dY, rZ, imm
|
|
|
|
const MachineOperand &MOBaseReg = MI.getOperand(1);
|
|
|
|
const MachineOperand &MOInsertedReg = MI.getOperand(2);
|
2018-01-11 22:30:43 +00:00
|
|
|
if (MOInsertedReg.isUndef())
|
|
|
|
return false;
|
2014-08-22 18:05:22 +00:00
|
|
|
const MachineOperand &MOIndex = MI.getOperand(3);
|
|
|
|
BaseReg.Reg = MOBaseReg.getReg();
|
|
|
|
BaseReg.SubReg = MOBaseReg.getSubReg();
|
|
|
|
|
|
|
|
InsertedReg.Reg = MOInsertedReg.getReg();
|
|
|
|
InsertedReg.SubReg = MOInsertedReg.getSubReg();
|
|
|
|
InsertedReg.SubIdx = MOIndex.getImm() == 0 ? ARM::ssub_0 : ARM::ssub_1;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
llvm_unreachable("Target dependent opcode missing");
|
|
|
|
}
|
2018-08-22 20:34:06 +00:00
|
|
|
|
|
|
|
std::pair<unsigned, unsigned>
|
|
|
|
ARMBaseInstrInfo::decomposeMachineOperandsTargetFlags(unsigned TF) const {
|
|
|
|
const unsigned Mask = ARMII::MO_OPTION_MASK;
|
|
|
|
return std::make_pair(TF & Mask, TF & ~Mask);
|
|
|
|
}
|
|
|
|
|
|
|
|
ArrayRef<std::pair<unsigned, const char *>>
|
|
|
|
ARMBaseInstrInfo::getSerializableDirectMachineOperandTargetFlags() const {
|
|
|
|
using namespace ARMII;
|
|
|
|
|
|
|
|
static const std::pair<unsigned, const char *> TargetFlags[] = {
|
|
|
|
{MO_LO16, "arm-lo16"}, {MO_HI16, "arm-hi16"}};
|
|
|
|
return makeArrayRef(TargetFlags);
|
|
|
|
}
|
|
|
|
|
|
|
|
ArrayRef<std::pair<unsigned, const char *>>
|
|
|
|
ARMBaseInstrInfo::getSerializableBitmaskMachineOperandTargetFlags() const {
|
|
|
|
using namespace ARMII;
|
|
|
|
|
|
|
|
static const std::pair<unsigned, const char *> TargetFlags[] = {
|
2018-08-31 08:00:25 +00:00
|
|
|
{MO_COFFSTUB, "arm-coffstub"},
|
2018-08-22 20:34:06 +00:00
|
|
|
{MO_GOT, "arm-got"},
|
|
|
|
{MO_SBREL, "arm-sbrel"},
|
|
|
|
{MO_DLLIMPORT, "arm-dllimport"},
|
|
|
|
{MO_SECREL, "arm-secrel"},
|
|
|
|
{MO_NONLAZY, "arm-nonlazy"}};
|
|
|
|
return makeArrayRef(TargetFlags);
|
|
|
|
}
|
2019-04-23 12:11:26 +00:00
|
|
|
|
[DebugInfo] Make describeLoadedValue() reg aware
Summary:
Currently the describeLoadedValue() hook is assumed to describe the
value of the instruction's first explicit define. The hook will not be
called for instructions with more than one explicit define.
This commit adds a register parameter to the describeLoadedValue() hook,
and invokes the hook for all registers in the worklist.
This will allow us to for example describe instructions which produce
more than two parameters' values; e.g. Hexagon's various combine
instructions.
This also fixes situations in our downstream target where we may pass
smaller parameters in the high part of a register. If such a parameter's
value is produced by a larger copy instruction, we can't describe the
call site value using the super-register, and we instead need to know
which sub-register that should be used.
This also allows us to handle cases like this:
$ebx = [...]
$rdi = MOVSX64rr32 $ebx
$esi = MOV32rr $edi
CALL64pcrel32 @call
The hook will first be invoked for the MOV32rr instruction, which will
say that @call's second parameter (passed in $esi) is described by $edi.
As $edi is not preserved it will be added to the worklist. When we get
to the MOVSX64rr32 instruction, we need to describe two values; the
sign-extended value of $ebx -> $rdi for the first parameter, and $ebx ->
$edi for the second parameter, which is now possible.
This commit modifies the dbgcall-site-lea-interpretation.mir test case.
In the test case, the values of some 32-bit parameters were produced
with LEA64r. Perhaps we can in general cases handle such by emitting
expressions that AND out the lower 32-bits, but I have not been able to
land in a case where a LEA64r is used for a 32-bit parameter instead of
LEA64_32 from C code.
I have not found a case where it would be useful to describe parameters
using implicit defines, so in this patch the hook is still only invoked
for explicit defines of forwarding registers.
Reviewers: djtodoro, NikolaPrica, aprantl, vsk
Reviewed By: djtodoro, vsk
Subscribers: ormris, hiraditya, llvm-commits
Tags: #debug-info, #llvm
Differential Revision: https://reviews.llvm.org/D70431
2019-12-09 10:46:16 +01:00
|
|
|
Optional<RegImmPair> ARMBaseInstrInfo::isAddImmediate(const MachineInstr &MI,
|
|
|
|
Register Reg) const {
|
2019-10-30 11:04:53 +01:00
|
|
|
int Sign = 1;
|
|
|
|
unsigned Opcode = MI.getOpcode();
|
[DebugInfo] Make describeLoadedValue() reg aware
Summary:
Currently the describeLoadedValue() hook is assumed to describe the
value of the instruction's first explicit define. The hook will not be
called for instructions with more than one explicit define.
This commit adds a register parameter to the describeLoadedValue() hook,
and invokes the hook for all registers in the worklist.
This will allow us to for example describe instructions which produce
more than two parameters' values; e.g. Hexagon's various combine
instructions.
This also fixes situations in our downstream target where we may pass
smaller parameters in the high part of a register. If such a parameter's
value is produced by a larger copy instruction, we can't describe the
call site value using the super-register, and we instead need to know
which sub-register that should be used.
This also allows us to handle cases like this:
$ebx = [...]
$rdi = MOVSX64rr32 $ebx
$esi = MOV32rr $edi
CALL64pcrel32 @call
The hook will first be invoked for the MOV32rr instruction, which will
say that @call's second parameter (passed in $esi) is described by $edi.
As $edi is not preserved it will be added to the worklist. When we get
to the MOVSX64rr32 instruction, we need to describe two values; the
sign-extended value of $ebx -> $rdi for the first parameter, and $ebx ->
$edi for the second parameter, which is now possible.
This commit modifies the dbgcall-site-lea-interpretation.mir test case.
In the test case, the values of some 32-bit parameters were produced
with LEA64r. Perhaps we can in general cases handle such by emitting
expressions that AND out the lower 32-bits, but I have not been able to
land in a case where a LEA64r is used for a 32-bit parameter instead of
LEA64_32 from C code.
I have not found a case where it would be useful to describe parameters
using implicit defines, so in this patch the hook is still only invoked
for explicit defines of forwarding registers.
Reviewers: djtodoro, NikolaPrica, aprantl, vsk
Reviewed By: djtodoro, vsk
Subscribers: ormris, hiraditya, llvm-commits
Tags: #debug-info, #llvm
Differential Revision: https://reviews.llvm.org/D70431
2019-12-09 10:46:16 +01:00
|
|
|
int64_t Offset = 0;
|
|
|
|
|
|
|
|
// TODO: Handle cases where Reg is a super- or sub-register of the
|
|
|
|
// destination register.
|
2020-02-27 10:30:41 +01:00
|
|
|
const MachineOperand &Op0 = MI.getOperand(0);
|
|
|
|
if (!Op0.isReg() || Reg != Op0.getReg())
|
[DebugInfo] Make describeLoadedValue() reg aware
Summary:
Currently the describeLoadedValue() hook is assumed to describe the
value of the instruction's first explicit define. The hook will not be
called for instructions with more than one explicit define.
This commit adds a register parameter to the describeLoadedValue() hook,
and invokes the hook for all registers in the worklist.
This will allow us to for example describe instructions which produce
more than two parameters' values; e.g. Hexagon's various combine
instructions.
This also fixes situations in our downstream target where we may pass
smaller parameters in the high part of a register. If such a parameter's
value is produced by a larger copy instruction, we can't describe the
call site value using the super-register, and we instead need to know
which sub-register that should be used.
This also allows us to handle cases like this:
$ebx = [...]
$rdi = MOVSX64rr32 $ebx
$esi = MOV32rr $edi
CALL64pcrel32 @call
The hook will first be invoked for the MOV32rr instruction, which will
say that @call's second parameter (passed in $esi) is described by $edi.
As $edi is not preserved it will be added to the worklist. When we get
to the MOVSX64rr32 instruction, we need to describe two values; the
sign-extended value of $ebx -> $rdi for the first parameter, and $ebx ->
$edi for the second parameter, which is now possible.
This commit modifies the dbgcall-site-lea-interpretation.mir test case.
In the test case, the values of some 32-bit parameters were produced
with LEA64r. Perhaps we can in general cases handle such by emitting
expressions that AND out the lower 32-bits, but I have not been able to
land in a case where a LEA64r is used for a 32-bit parameter instead of
LEA64_32 from C code.
I have not found a case where it would be useful to describe parameters
using implicit defines, so in this patch the hook is still only invoked
for explicit defines of forwarding registers.
Reviewers: djtodoro, NikolaPrica, aprantl, vsk
Reviewed By: djtodoro, vsk
Subscribers: ormris, hiraditya, llvm-commits
Tags: #debug-info, #llvm
Differential Revision: https://reviews.llvm.org/D70431
2019-12-09 10:46:16 +01:00
|
|
|
return None;
|
2019-10-30 11:04:53 +01:00
|
|
|
|
|
|
|
// We describe SUBri or ADDri instructions.
|
|
|
|
if (Opcode == ARM::SUBri)
|
|
|
|
Sign = -1;
|
|
|
|
else if (Opcode != ARM::ADDri)
|
2019-11-08 11:19:58 +01:00
|
|
|
return None;
|
2019-10-30 11:04:53 +01:00
|
|
|
|
|
|
|
// TODO: Third operand can be global address (usually some string). Since
|
|
|
|
// strings can be relocated we cannot calculate their offsets for
|
|
|
|
// now.
|
2020-02-27 10:30:41 +01:00
|
|
|
if (!MI.getOperand(1).isReg() || !MI.getOperand(2).isImm())
|
2019-11-08 11:19:58 +01:00
|
|
|
return None;
|
2019-10-30 11:04:53 +01:00
|
|
|
|
|
|
|
Offset = MI.getOperand(2).getImm() * Sign;
|
[DebugInfo] Make describeLoadedValue() reg aware
Summary:
Currently the describeLoadedValue() hook is assumed to describe the
value of the instruction's first explicit define. The hook will not be
called for instructions with more than one explicit define.
This commit adds a register parameter to the describeLoadedValue() hook,
and invokes the hook for all registers in the worklist.
This will allow us to for example describe instructions which produce
more than two parameters' values; e.g. Hexagon's various combine
instructions.
This also fixes situations in our downstream target where we may pass
smaller parameters in the high part of a register. If such a parameter's
value is produced by a larger copy instruction, we can't describe the
call site value using the super-register, and we instead need to know
which sub-register that should be used.
This also allows us to handle cases like this:
$ebx = [...]
$rdi = MOVSX64rr32 $ebx
$esi = MOV32rr $edi
CALL64pcrel32 @call
The hook will first be invoked for the MOV32rr instruction, which will
say that @call's second parameter (passed in $esi) is described by $edi.
As $edi is not preserved it will be added to the worklist. When we get
to the MOVSX64rr32 instruction, we need to describe two values; the
sign-extended value of $ebx -> $rdi for the first parameter, and $ebx ->
$edi for the second parameter, which is now possible.
This commit modifies the dbgcall-site-lea-interpretation.mir test case.
In the test case, the values of some 32-bit parameters were produced
with LEA64r. Perhaps we can in general cases handle such by emitting
expressions that AND out the lower 32-bits, but I have not been able to
land in a case where a LEA64r is used for a 32-bit parameter instead of
LEA64_32 from C code.
I have not found a case where it would be useful to describe parameters
using implicit defines, so in this patch the hook is still only invoked
for explicit defines of forwarding registers.
Reviewers: djtodoro, NikolaPrica, aprantl, vsk
Reviewed By: djtodoro, vsk
Subscribers: ormris, hiraditya, llvm-commits
Tags: #debug-info, #llvm
Differential Revision: https://reviews.llvm.org/D70431
2019-12-09 10:46:16 +01:00
|
|
|
return RegImmPair{MI.getOperand(1).getReg(), Offset};
|
2019-10-30 11:04:53 +01:00
|
|
|
}
|
|
|
|
|
2019-04-23 12:11:26 +00:00
|
|
|
bool llvm::registerDefinedBetween(unsigned Reg,
|
|
|
|
MachineBasicBlock::iterator From,
|
|
|
|
MachineBasicBlock::iterator To,
|
|
|
|
const TargetRegisterInfo *TRI) {
|
|
|
|
for (auto I = From; I != To; ++I)
|
|
|
|
if (I->modifiesRegister(Reg, TRI))
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
MachineInstr *llvm::findCMPToFoldIntoCBZ(MachineInstr *Br,
|
|
|
|
const TargetRegisterInfo *TRI) {
|
|
|
|
// Search backwards to the instruction that defines CSPR. This may or not
|
|
|
|
// be a CMP, we check that after this loop. If we find another instruction
|
|
|
|
// that reads cpsr, we return nullptr.
|
|
|
|
MachineBasicBlock::iterator CmpMI = Br;
|
|
|
|
while (CmpMI != Br->getParent()->begin()) {
|
|
|
|
--CmpMI;
|
|
|
|
if (CmpMI->modifiesRegister(ARM::CPSR, TRI))
|
|
|
|
break;
|
|
|
|
if (CmpMI->readsRegister(ARM::CPSR, TRI))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check that this inst is a CMP r[0-7], #0 and that the register
|
|
|
|
// is not redefined between the cmp and the br.
|
|
|
|
if (CmpMI->getOpcode() != ARM::tCMPi8 && CmpMI->getOpcode() != ARM::t2CMPri)
|
|
|
|
return nullptr;
|
Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Partial reverts in:
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
X86FixupLEAs.cpp - Some functions return unsigned and arguably should be MCRegister
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
HexagonBitSimplify.cpp - Function takes BitTracker::RegisterRef which appears to be unsigned&
MachineVerifier.cpp - Ambiguous operator==() given MCRegister and const Register
PPCFastISel.cpp - No Register::operator-=()
PeepholeOptimizer.cpp - TargetInstrInfo::optimizeLoadInstr() takes an unsigned&
MachineTraceMetrics.cpp - MachineTraceMetrics lacks a suitable constructor
Manual fixups in:
ARMFastISel.cpp - ARMEmitLoad() now takes a Register& instead of unsigned&
HexagonSplitDouble.cpp - Ternary operator was ambiguous between unsigned/Register
HexagonConstExtenders.cpp - Has a local class named Register, used llvm::Register instead of Register.
PPCFastISel.cpp - PPCEmitLoad() now takes a Register& instead of unsigned&
Depends on D65919
Reviewers: arsenm, bogner, craig.topper, RKSimon
Reviewed By: arsenm
Subscribers: RKSimon, craig.topper, lenary, aemerson, wuzish, jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65962
llvm-svn: 369041
2019-08-15 19:22:08 +00:00
|
|
|
Register Reg = CmpMI->getOperand(0).getReg();
|
2020-04-07 17:28:53 -04:00
|
|
|
Register PredReg;
|
2019-04-23 12:11:26 +00:00
|
|
|
ARMCC::CondCodes Pred = getInstrPredicate(*CmpMI, PredReg);
|
|
|
|
if (Pred != ARMCC::AL || CmpMI->getOperand(1).getImm() != 0)
|
|
|
|
return nullptr;
|
|
|
|
if (!isARMLowRegister(Reg))
|
|
|
|
return nullptr;
|
|
|
|
if (registerDefinedBetween(Reg, CmpMI->getNextNode(), Br, TRI))
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
return &*CmpMI;
|
|
|
|
}
|
2019-09-03 11:06:24 +00:00
|
|
|
|
|
|
|
unsigned llvm::ConstantMaterializationCost(unsigned Val,
|
|
|
|
const ARMSubtarget *Subtarget,
|
|
|
|
bool ForCodesize) {
|
|
|
|
if (Subtarget->isThumb()) {
|
|
|
|
if (Val <= 255) // MOV
|
|
|
|
return ForCodesize ? 2 : 1;
|
|
|
|
if (Subtarget->hasV6T2Ops() && (Val <= 0xffff || // MOV
|
|
|
|
ARM_AM::getT2SOImmVal(Val) != -1 || // MOVW
|
|
|
|
ARM_AM::getT2SOImmVal(~Val) != -1)) // MVN
|
|
|
|
return ForCodesize ? 4 : 1;
|
|
|
|
if (Val <= 510) // MOV + ADDi8
|
|
|
|
return ForCodesize ? 4 : 2;
|
|
|
|
if (~Val <= 255) // MOV + MVN
|
|
|
|
return ForCodesize ? 4 : 2;
|
|
|
|
if (ARM_AM::isThumbImmShiftedVal(Val)) // MOV + LSL
|
|
|
|
return ForCodesize ? 4 : 2;
|
|
|
|
} else {
|
|
|
|
if (ARM_AM::getSOImmVal(Val) != -1) // MOV
|
|
|
|
return ForCodesize ? 4 : 1;
|
|
|
|
if (ARM_AM::getSOImmVal(~Val) != -1) // MVN
|
|
|
|
return ForCodesize ? 4 : 1;
|
|
|
|
if (Subtarget->hasV6T2Ops() && Val <= 0xffff) // MOVW
|
|
|
|
return ForCodesize ? 4 : 1;
|
|
|
|
if (ARM_AM::isSOImmTwoPartVal(Val)) // two instrs
|
|
|
|
return ForCodesize ? 8 : 2;
|
|
|
|
}
|
|
|
|
if (Subtarget->useMovt()) // MOVW + MOVT
|
|
|
|
return ForCodesize ? 8 : 2;
|
|
|
|
return ForCodesize ? 8 : 3; // Literal pool load
|
|
|
|
}
|
|
|
|
|
|
|
|
bool llvm::HasLowerConstantMaterializationCost(unsigned Val1, unsigned Val2,
|
|
|
|
const ARMSubtarget *Subtarget,
|
|
|
|
bool ForCodesize) {
|
|
|
|
// Check with ForCodesize
|
|
|
|
unsigned Cost1 = ConstantMaterializationCost(Val1, Subtarget, ForCodesize);
|
|
|
|
unsigned Cost2 = ConstantMaterializationCost(Val2, Subtarget, ForCodesize);
|
|
|
|
if (Cost1 < Cost2)
|
|
|
|
return true;
|
|
|
|
if (Cost1 > Cost2)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// If they are equal, try with !ForCodesize
|
|
|
|
return ConstantMaterializationCost(Val1, Subtarget, !ForCodesize) <
|
|
|
|
ConstantMaterializationCost(Val2, Subtarget, !ForCodesize);
|
|
|
|
}
|
2020-05-15 08:44:23 +02:00
|
|
|
|
|
|
|
/// Constants defining how certain sequences should be outlined.
|
|
|
|
/// This encompasses how an outlined function should be called, and what kind of
|
|
|
|
/// frame should be emitted for that outlined function.
|
|
|
|
///
|
|
|
|
/// \p MachineOutlinerTailCall implies that the function is being created from
|
|
|
|
/// a sequence of instructions ending in a return.
|
|
|
|
///
|
|
|
|
/// That is,
|
|
|
|
///
|
|
|
|
/// I1 OUTLINED_FUNCTION:
|
|
|
|
/// I2 --> B OUTLINED_FUNCTION I1
|
|
|
|
/// BX LR I2
|
|
|
|
/// BX LR
|
|
|
|
///
|
|
|
|
/// +-------------------------+--------+-----+
|
|
|
|
/// | | Thumb2 | ARM |
|
|
|
|
/// +-------------------------+--------+-----+
|
|
|
|
/// | Call overhead in Bytes | 4 | 4 |
|
|
|
|
/// | Frame overhead in Bytes | 0 | 0 |
|
|
|
|
/// | Stack fixup required | No | No |
|
|
|
|
/// +-------------------------+--------+-----+
|
|
|
|
///
|
|
|
|
/// \p MachineOutlinerThunk implies that the function is being created from
|
|
|
|
/// a sequence of instructions ending in a call. The outlined function is
|
|
|
|
/// called with a BL instruction, and the outlined function tail-calls the
|
|
|
|
/// original call destination.
|
|
|
|
///
|
|
|
|
/// That is,
|
|
|
|
///
|
|
|
|
/// I1 OUTLINED_FUNCTION:
|
|
|
|
/// I2 --> BL OUTLINED_FUNCTION I1
|
|
|
|
/// BL f I2
|
|
|
|
/// B f
|
|
|
|
///
|
|
|
|
/// +-------------------------+--------+-----+
|
|
|
|
/// | | Thumb2 | ARM |
|
|
|
|
/// +-------------------------+--------+-----+
|
|
|
|
/// | Call overhead in Bytes | 4 | 4 |
|
|
|
|
/// | Frame overhead in Bytes | 0 | 0 |
|
|
|
|
/// | Stack fixup required | No | No |
|
|
|
|
/// +-------------------------+--------+-----+
|
2020-06-11 08:45:46 +02:00
|
|
|
///
|
|
|
|
/// \p MachineOutlinerNoLRSave implies that the function should be called using
|
|
|
|
/// a BL instruction, but doesn't require LR to be saved and restored. This
|
|
|
|
/// happens when LR is known to be dead.
|
|
|
|
///
|
|
|
|
/// That is,
|
|
|
|
///
|
|
|
|
/// I1 OUTLINED_FUNCTION:
|
|
|
|
/// I2 --> BL OUTLINED_FUNCTION I1
|
|
|
|
/// I3 I2
|
|
|
|
/// I3
|
|
|
|
/// BX LR
|
|
|
|
///
|
|
|
|
/// +-------------------------+--------+-----+
|
|
|
|
/// | | Thumb2 | ARM |
|
|
|
|
/// +-------------------------+--------+-----+
|
|
|
|
/// | Call overhead in Bytes | 4 | 4 |
|
|
|
|
/// | Frame overhead in Bytes | 4 | 4 |
|
|
|
|
/// | Stack fixup required | No | No |
|
|
|
|
/// +-------------------------+--------+-----+
|
2020-06-15 15:22:08 +02:00
|
|
|
///
|
|
|
|
/// \p MachineOutlinerRegSave implies that the function should be called with a
|
|
|
|
/// save and restore of LR to an available register. This allows us to avoid
|
|
|
|
/// stack fixups. Note that this outlining variant is compatible with the
|
|
|
|
/// NoLRSave case.
|
|
|
|
///
|
|
|
|
/// That is,
|
|
|
|
///
|
|
|
|
/// I1 Save LR OUTLINED_FUNCTION:
|
|
|
|
/// I2 --> BL OUTLINED_FUNCTION I1
|
|
|
|
/// I3 Restore LR I2
|
|
|
|
/// I3
|
|
|
|
/// BX LR
|
|
|
|
///
|
|
|
|
/// +-------------------------+--------+-----+
|
|
|
|
/// | | Thumb2 | ARM |
|
|
|
|
/// +-------------------------+--------+-----+
|
|
|
|
/// | Call overhead in Bytes | 8 | 12 |
|
|
|
|
/// | Frame overhead in Bytes | 2 | 4 |
|
|
|
|
/// | Stack fixup required | No | No |
|
|
|
|
/// +-------------------------+--------+-----+
|
2020-05-15 08:44:23 +02:00
|
|
|
|
2020-06-11 08:45:46 +02:00
|
|
|
enum MachineOutlinerClass {
|
|
|
|
MachineOutlinerTailCall,
|
|
|
|
MachineOutlinerThunk,
|
2020-06-15 15:22:08 +02:00
|
|
|
MachineOutlinerNoLRSave,
|
|
|
|
MachineOutlinerRegSave
|
2020-06-11 08:45:46 +02:00
|
|
|
};
|
2020-05-15 08:44:23 +02:00
|
|
|
|
|
|
|
enum MachineOutlinerMBBFlags {
|
|
|
|
LRUnavailableSomewhere = 0x2,
|
|
|
|
HasCalls = 0x4,
|
|
|
|
UnsafeRegsDead = 0x8
|
|
|
|
};
|
|
|
|
|
|
|
|
struct OutlinerCosts {
|
|
|
|
const int CallTailCall;
|
|
|
|
const int FrameTailCall;
|
|
|
|
const int CallThunk;
|
|
|
|
const int FrameThunk;
|
2020-06-11 08:45:46 +02:00
|
|
|
const int CallNoLRSave;
|
|
|
|
const int FrameNoLRSave;
|
2020-06-15 15:22:08 +02:00
|
|
|
const int CallRegSave;
|
|
|
|
const int FrameRegSave;
|
2020-05-15 08:44:23 +02:00
|
|
|
|
|
|
|
OutlinerCosts(const ARMSubtarget &target)
|
|
|
|
: CallTailCall(target.isThumb() ? 4 : 4),
|
|
|
|
FrameTailCall(target.isThumb() ? 0 : 0),
|
|
|
|
CallThunk(target.isThumb() ? 4 : 4),
|
2020-06-11 08:45:46 +02:00
|
|
|
FrameThunk(target.isThumb() ? 0 : 0),
|
|
|
|
CallNoLRSave(target.isThumb() ? 4 : 4),
|
2020-06-15 15:22:08 +02:00
|
|
|
FrameNoLRSave(target.isThumb() ? 4 : 4),
|
|
|
|
CallRegSave(target.isThumb() ? 8 : 12),
|
|
|
|
FrameRegSave(target.isThumb() ? 2 : 4) {}
|
2020-05-15 08:44:23 +02:00
|
|
|
};
|
|
|
|
|
2020-06-15 15:22:08 +02:00
|
|
|
unsigned
|
|
|
|
ARMBaseInstrInfo::findRegisterToSaveLRTo(const outliner::Candidate &C) const {
|
|
|
|
assert(C.LRUWasSet && "LRU wasn't set?");
|
|
|
|
MachineFunction *MF = C.getMF();
|
|
|
|
const ARMBaseRegisterInfo *ARI = static_cast<const ARMBaseRegisterInfo *>(
|
|
|
|
MF->getSubtarget().getRegisterInfo());
|
|
|
|
|
|
|
|
BitVector regsReserved = ARI->getReservedRegs(*MF);
|
|
|
|
// Check if there is an available register across the sequence that we can
|
|
|
|
// use.
|
|
|
|
for (unsigned Reg : ARM::rGPRRegClass) {
|
|
|
|
if (!(Reg < regsReserved.size() && regsReserved.test(Reg)) &&
|
|
|
|
Reg != ARM::LR && // LR is not reserved, but don't use it.
|
|
|
|
Reg != ARM::R12 && // R12 is not guaranteed to be preserved.
|
|
|
|
C.LRU.available(Reg) && C.UsedInSequence.available(Reg))
|
|
|
|
return Reg;
|
|
|
|
}
|
|
|
|
|
|
|
|
// No suitable register. Return 0.
|
|
|
|
return 0u;
|
|
|
|
}
|
|
|
|
|
2020-05-15 08:44:23 +02:00
|
|
|
outliner::OutlinedFunction ARMBaseInstrInfo::getOutliningCandidateInfo(
|
|
|
|
std::vector<outliner::Candidate> &RepeatedSequenceLocs) const {
|
|
|
|
outliner::Candidate &FirstCand = RepeatedSequenceLocs[0];
|
|
|
|
unsigned SequenceSize =
|
|
|
|
std::accumulate(FirstCand.front(), std::next(FirstCand.back()), 0,
|
|
|
|
[this](unsigned Sum, const MachineInstr &MI) {
|
|
|
|
return Sum + getInstSizeInBytes(MI);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Properties about candidate MBBs that hold for all of them.
|
|
|
|
unsigned FlagsSetInAll = 0xF;
|
|
|
|
|
|
|
|
// Compute liveness information for each candidate, and set FlagsSetInAll.
|
|
|
|
const TargetRegisterInfo &TRI = getRegisterInfo();
|
|
|
|
std::for_each(
|
|
|
|
RepeatedSequenceLocs.begin(), RepeatedSequenceLocs.end(),
|
|
|
|
[&FlagsSetInAll](outliner::Candidate &C) { FlagsSetInAll &= C.Flags; });
|
|
|
|
|
|
|
|
// According to the ARM Procedure Call Standard, the following are
|
|
|
|
// undefined on entry/exit from a function call:
|
|
|
|
//
|
|
|
|
// * Register R12(IP),
|
|
|
|
// * Condition codes (and thus the CPSR register)
|
|
|
|
//
|
|
|
|
// Since we control the instructions which are part of the outlined regions
|
|
|
|
// we don't need to be fully compliant with the AAPCS, but we have to
|
|
|
|
// guarantee that if a veneer is inserted at link time the code is still
|
|
|
|
// correct. Because of this, we can't outline any sequence of instructions
|
|
|
|
// where one of these registers is live into/across it. Thus, we need to
|
|
|
|
// delete those candidates.
|
|
|
|
auto CantGuaranteeValueAcrossCall = [&TRI](outliner::Candidate &C) {
|
|
|
|
// If the unsafe registers in this block are all dead, then we don't need
|
|
|
|
// to compute liveness here.
|
|
|
|
if (C.Flags & UnsafeRegsDead)
|
|
|
|
return false;
|
|
|
|
C.initLRU(TRI);
|
|
|
|
LiveRegUnits LRU = C.LRU;
|
|
|
|
return (!LRU.available(ARM::R12) || !LRU.available(ARM::CPSR));
|
|
|
|
};
|
|
|
|
|
|
|
|
// Are there any candidates where those registers are live?
|
|
|
|
if (!(FlagsSetInAll & UnsafeRegsDead)) {
|
|
|
|
// Erase every candidate that violates the restrictions above. (It could be
|
|
|
|
// true that we have viable candidates, so it's not worth bailing out in
|
|
|
|
// the case that, say, 1 out of 20 candidates violate the restructions.)
|
|
|
|
RepeatedSequenceLocs.erase(std::remove_if(RepeatedSequenceLocs.begin(),
|
|
|
|
RepeatedSequenceLocs.end(),
|
|
|
|
CantGuaranteeValueAcrossCall),
|
|
|
|
RepeatedSequenceLocs.end());
|
|
|
|
|
|
|
|
// If the sequence doesn't have enough candidates left, then we're done.
|
|
|
|
if (RepeatedSequenceLocs.size() < 2)
|
|
|
|
return outliner::OutlinedFunction();
|
|
|
|
}
|
|
|
|
|
|
|
|
// At this point, we have only "safe" candidates to outline. Figure out
|
|
|
|
// frame + call instruction information.
|
|
|
|
|
|
|
|
unsigned LastInstrOpcode = RepeatedSequenceLocs[0].back()->getOpcode();
|
|
|
|
|
|
|
|
// Helper lambda which sets call information for every candidate.
|
|
|
|
auto SetCandidateCallInfo =
|
|
|
|
[&RepeatedSequenceLocs](unsigned CallID, unsigned NumBytesForCall) {
|
|
|
|
for (outliner::Candidate &C : RepeatedSequenceLocs)
|
|
|
|
C.setCallInfo(CallID, NumBytesForCall);
|
|
|
|
};
|
|
|
|
|
2020-06-04 13:12:26 +02:00
|
|
|
OutlinerCosts Costs(Subtarget);
|
2020-05-15 08:44:23 +02:00
|
|
|
unsigned FrameID = 0;
|
|
|
|
unsigned NumBytesToCreateFrame = 0;
|
|
|
|
|
|
|
|
// If the last instruction in any candidate is a terminator, then we should
|
|
|
|
// tail call all of the candidates.
|
|
|
|
if (RepeatedSequenceLocs[0].back()->isTerminator()) {
|
|
|
|
FrameID = MachineOutlinerTailCall;
|
2020-06-04 13:12:26 +02:00
|
|
|
NumBytesToCreateFrame = Costs.FrameTailCall;
|
|
|
|
SetCandidateCallInfo(MachineOutlinerTailCall, Costs.CallTailCall);
|
2020-05-15 08:44:23 +02:00
|
|
|
} else if (LastInstrOpcode == ARM::BL || LastInstrOpcode == ARM::BLX ||
|
|
|
|
LastInstrOpcode == ARM::tBL || LastInstrOpcode == ARM::tBLXr ||
|
|
|
|
LastInstrOpcode == ARM::tBLXi) {
|
|
|
|
FrameID = MachineOutlinerThunk;
|
2020-06-04 13:12:26 +02:00
|
|
|
NumBytesToCreateFrame = Costs.FrameThunk;
|
|
|
|
SetCandidateCallInfo(MachineOutlinerThunk, Costs.CallThunk);
|
2020-06-11 08:45:46 +02:00
|
|
|
} else {
|
|
|
|
// We need to decide how to emit calls + frames. We can always emit the same
|
|
|
|
// frame if we don't need to save to the stack.
|
|
|
|
unsigned NumBytesNoStackCalls = 0;
|
|
|
|
std::vector<outliner::Candidate> CandidatesWithoutStackFixups;
|
|
|
|
|
|
|
|
for (outliner::Candidate &C : RepeatedSequenceLocs) {
|
|
|
|
C.initLRU(TRI);
|
|
|
|
|
|
|
|
// Is LR available? If so, we don't need a save.
|
|
|
|
if (C.LRU.available(ARM::LR)) {
|
|
|
|
FrameID = MachineOutlinerNoLRSave;
|
|
|
|
NumBytesNoStackCalls += Costs.CallNoLRSave;
|
|
|
|
C.setCallInfo(MachineOutlinerNoLRSave, Costs.CallNoLRSave);
|
|
|
|
CandidatesWithoutStackFixups.push_back(C);
|
|
|
|
}
|
2020-06-15 15:22:08 +02:00
|
|
|
|
|
|
|
// Is an unused register available? If so, we won't modify the stack, so
|
|
|
|
// we can outline with the same frame type as those that don't save LR.
|
|
|
|
else if (findRegisterToSaveLRTo(C)) {
|
|
|
|
FrameID = MachineOutlinerRegSave;
|
|
|
|
NumBytesNoStackCalls += Costs.CallRegSave;
|
|
|
|
C.setCallInfo(MachineOutlinerRegSave, Costs.CallRegSave);
|
|
|
|
CandidatesWithoutStackFixups.push_back(C);
|
|
|
|
}
|
2020-06-11 08:45:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!CandidatesWithoutStackFixups.empty()) {
|
|
|
|
RepeatedSequenceLocs = CandidatesWithoutStackFixups;
|
|
|
|
} else
|
|
|
|
return outliner::OutlinedFunction();
|
|
|
|
}
|
2020-05-15 08:44:23 +02:00
|
|
|
|
|
|
|
return outliner::OutlinedFunction(RepeatedSequenceLocs, SequenceSize,
|
|
|
|
NumBytesToCreateFrame, FrameID);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ARMBaseInstrInfo::isFunctionSafeToOutlineFrom(
|
|
|
|
MachineFunction &MF, bool OutlineFromLinkOnceODRs) const {
|
|
|
|
const Function &F = MF.getFunction();
|
|
|
|
|
|
|
|
// Can F be deduplicated by the linker? If it can, don't outline from it.
|
|
|
|
if (!OutlineFromLinkOnceODRs && F.hasLinkOnceODRLinkage())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Don't outline from functions with section markings; the program could
|
|
|
|
// expect that all the code is in the named section.
|
|
|
|
// FIXME: Allow outlining from multiple functions with the same section
|
|
|
|
// marking.
|
|
|
|
if (F.hasSection())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// FIXME: Thumb1 outlining is not handled
|
|
|
|
if (MF.getInfo<ARMFunctionInfo>()->isThumb1OnlyFunction())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// It's safe to outline from MF.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ARMBaseInstrInfo::isMBBSafeToOutlineFrom(MachineBasicBlock &MBB,
|
|
|
|
unsigned &Flags) const {
|
|
|
|
// Check if LR is available through all of the MBB. If it's not, then set
|
|
|
|
// a flag.
|
|
|
|
assert(MBB.getParent()->getRegInfo().tracksLiveness() &&
|
|
|
|
"Suitable Machine Function for outlining must track liveness");
|
|
|
|
|
|
|
|
LiveRegUnits LRU(getRegisterInfo());
|
|
|
|
|
|
|
|
std::for_each(MBB.rbegin(), MBB.rend(),
|
|
|
|
[&LRU](MachineInstr &MI) { LRU.accumulate(MI); });
|
|
|
|
|
|
|
|
// Check if each of the unsafe registers are available...
|
|
|
|
bool R12AvailableInBlock = LRU.available(ARM::R12);
|
|
|
|
bool CPSRAvailableInBlock = LRU.available(ARM::CPSR);
|
|
|
|
|
|
|
|
// If all of these are dead (and not live out), we know we don't have to check
|
|
|
|
// them later.
|
|
|
|
if (R12AvailableInBlock && CPSRAvailableInBlock)
|
|
|
|
Flags |= MachineOutlinerMBBFlags::UnsafeRegsDead;
|
|
|
|
|
|
|
|
// Now, add the live outs to the set.
|
|
|
|
LRU.addLiveOuts(MBB);
|
|
|
|
|
|
|
|
// If any of these registers is available in the MBB, but also a live out of
|
|
|
|
// the block, then we know outlining is unsafe.
|
|
|
|
if (R12AvailableInBlock && !LRU.available(ARM::R12))
|
|
|
|
return false;
|
|
|
|
if (CPSRAvailableInBlock && !LRU.available(ARM::CPSR))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Check if there's a call inside this MachineBasicBlock. If there is, then
|
|
|
|
// set a flag.
|
|
|
|
if (any_of(MBB, [](MachineInstr &MI) { return MI.isCall(); }))
|
|
|
|
Flags |= MachineOutlinerMBBFlags::HasCalls;
|
|
|
|
|
|
|
|
if (!LRU.available(ARM::LR))
|
|
|
|
Flags |= MachineOutlinerMBBFlags::LRUnavailableSomewhere;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
outliner::InstrType
|
|
|
|
ARMBaseInstrInfo::getOutliningType(MachineBasicBlock::iterator &MIT,
|
|
|
|
unsigned Flags) const {
|
|
|
|
MachineInstr &MI = *MIT;
|
|
|
|
const TargetRegisterInfo *TRI = &getRegisterInfo();
|
|
|
|
|
|
|
|
// Be conservative with inline ASM
|
|
|
|
if (MI.isInlineAsm())
|
|
|
|
return outliner::InstrType::Illegal;
|
|
|
|
|
|
|
|
// Don't allow debug values to impact outlining type.
|
|
|
|
if (MI.isDebugInstr() || MI.isIndirectDebugValue())
|
|
|
|
return outliner::InstrType::Invisible;
|
|
|
|
|
|
|
|
// At this point, KILL or IMPLICIT_DEF instructions don't really tell us much
|
|
|
|
// so we can go ahead and skip over them.
|
|
|
|
if (MI.isKill() || MI.isImplicitDef())
|
|
|
|
return outliner::InstrType::Invisible;
|
|
|
|
|
|
|
|
// PIC instructions contain labels, outlining them would break offset
|
|
|
|
// computing. unsigned Opc = MI.getOpcode();
|
|
|
|
unsigned Opc = MI.getOpcode();
|
|
|
|
if (Opc == ARM::tPICADD || Opc == ARM::PICADD || Opc == ARM::PICSTR ||
|
|
|
|
Opc == ARM::PICSTRB || Opc == ARM::PICSTRH || Opc == ARM::PICLDR ||
|
|
|
|
Opc == ARM::PICLDRB || Opc == ARM::PICLDRH || Opc == ARM::PICLDRSB ||
|
|
|
|
Opc == ARM::PICLDRSH || Opc == ARM::t2LDRpci_pic ||
|
|
|
|
Opc == ARM::t2MOVi16_ga_pcrel || Opc == ARM::t2MOVTi16_ga_pcrel ||
|
|
|
|
Opc == ARM::t2MOV_ga_pcrel)
|
|
|
|
return outliner::InstrType::Illegal;
|
|
|
|
|
|
|
|
// Be conservative with ARMv8.1 MVE instructions.
|
|
|
|
if (Opc == ARM::t2BF_LabelPseudo || Opc == ARM::t2DoLoopStart ||
|
|
|
|
Opc == ARM::t2WhileLoopStart || Opc == ARM::t2LoopDec ||
|
|
|
|
Opc == ARM::t2LoopEnd)
|
|
|
|
return outliner::InstrType::Illegal;
|
|
|
|
|
|
|
|
const MCInstrDesc &MCID = MI.getDesc();
|
|
|
|
uint64_t MIFlags = MCID.TSFlags;
|
|
|
|
if ((MIFlags & ARMII::DomainMask) == ARMII::DomainMVE)
|
|
|
|
return outliner::InstrType::Illegal;
|
|
|
|
|
|
|
|
// Is this a terminator for a basic block?
|
|
|
|
if (MI.isTerminator()) {
|
|
|
|
// Don't outline if the branch is not unconditional.
|
|
|
|
if (isPredicated(MI))
|
|
|
|
return outliner::InstrType::Illegal;
|
|
|
|
|
|
|
|
// Is this the end of a function?
|
|
|
|
if (MI.getParent()->succ_empty())
|
|
|
|
return outliner::InstrType::Legal;
|
|
|
|
|
|
|
|
// It's not, so don't outline it.
|
|
|
|
return outliner::InstrType::Illegal;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure none of the operands are un-outlinable.
|
|
|
|
for (const MachineOperand &MOP : MI.operands()) {
|
|
|
|
if (MOP.isCPI() || MOP.isJTI() || MOP.isCFIIndex() || MOP.isFI() ||
|
|
|
|
MOP.isTargetIndex())
|
|
|
|
return outliner::InstrType::Illegal;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Don't outline if link register or program counter value are used.
|
|
|
|
if (MI.readsRegister(ARM::LR, TRI) || MI.readsRegister(ARM::PC, TRI))
|
|
|
|
return outliner::InstrType::Illegal;
|
|
|
|
|
|
|
|
if (MI.isCall()) {
|
|
|
|
// If we don't know anything about the callee, assume it depends on the
|
|
|
|
// stack layout of the caller. In that case, it's only legal to outline
|
2020-06-20 00:05:32 -07:00
|
|
|
// as a tail-call. Explicitly list the call instructions we know about so
|
|
|
|
// we don't get unexpected results with call pseudo-instructions.
|
2020-05-15 08:44:23 +02:00
|
|
|
auto UnknownCallOutlineType = outliner::InstrType::Illegal;
|
|
|
|
if (Opc == ARM::BL || Opc == ARM::tBL || Opc == ARM::BLX ||
|
|
|
|
Opc == ARM::tBLXr || Opc == ARM::tBLXi)
|
|
|
|
UnknownCallOutlineType = outliner::InstrType::LegalTerminator;
|
|
|
|
|
|
|
|
return UnknownCallOutlineType;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Since calls are handled, don't touch LR or PC
|
|
|
|
if (MI.modifiesRegister(ARM::LR, TRI) || MI.modifiesRegister(ARM::PC, TRI))
|
|
|
|
return outliner::InstrType::Illegal;
|
|
|
|
|
2020-06-11 08:45:46 +02:00
|
|
|
// Does this use the stack?
|
|
|
|
if (MI.modifiesRegister(ARM::SP, TRI) || MI.readsRegister(ARM::SP, TRI)) {
|
|
|
|
// True if there is no chance that any outlined candidate from this range
|
|
|
|
// could require stack fixups. That is, both
|
|
|
|
// * LR is available in the range (No save/restore around call)
|
|
|
|
// * The range doesn't include calls (No save/restore in outlined frame)
|
|
|
|
// are true.
|
|
|
|
// FIXME: This is very restrictive; the flags check the whole block,
|
|
|
|
// not just the bit we will try to outline.
|
|
|
|
bool MightNeedStackFixUp =
|
|
|
|
(Flags & (MachineOutlinerMBBFlags::LRUnavailableSomewhere |
|
|
|
|
MachineOutlinerMBBFlags::HasCalls));
|
|
|
|
|
|
|
|
if (!MightNeedStackFixUp)
|
|
|
|
return outliner::InstrType::Legal;
|
|
|
|
|
|
|
|
return outliner::InstrType::Illegal;
|
|
|
|
}
|
|
|
|
|
2020-05-15 08:44:23 +02:00
|
|
|
// Be conservative with IT blocks.
|
|
|
|
if (MI.readsRegister(ARM::ITSTATE, TRI) ||
|
|
|
|
MI.modifiesRegister(ARM::ITSTATE, TRI))
|
|
|
|
return outliner::InstrType::Illegal;
|
|
|
|
|
|
|
|
// Don't outline positions.
|
|
|
|
if (MI.isPosition())
|
|
|
|
return outliner::InstrType::Illegal;
|
|
|
|
|
|
|
|
return outliner::InstrType::Legal;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ARMBaseInstrInfo::buildOutlinedFrame(
|
|
|
|
MachineBasicBlock &MBB, MachineFunction &MF,
|
|
|
|
const outliner::OutlinedFunction &OF) const {
|
2020-06-11 08:45:46 +02:00
|
|
|
// Nothing is needed for tail-calls.
|
|
|
|
if (OF.FrameConstructionID == MachineOutlinerTailCall)
|
|
|
|
return;
|
|
|
|
|
2020-05-15 08:44:23 +02:00
|
|
|
// For thunk outlining, rewrite the last instruction from a call to a
|
|
|
|
// tail-call.
|
|
|
|
if (OF.FrameConstructionID == MachineOutlinerThunk) {
|
|
|
|
MachineInstr *Call = &*--MBB.instr_end();
|
|
|
|
bool isThumb = Subtarget.isThumb();
|
|
|
|
unsigned FuncOp = isThumb ? 2 : 0;
|
|
|
|
unsigned Opc = Call->getOperand(FuncOp).isReg()
|
|
|
|
? isThumb ? ARM::tTAILJMPr : ARM::TAILJMPr
|
|
|
|
: isThumb ? Subtarget.isTargetMachO() ? ARM::tTAILJMPd
|
|
|
|
: ARM::tTAILJMPdND
|
|
|
|
: ARM::TAILJMPd;
|
|
|
|
MachineInstrBuilder MIB = BuildMI(MBB, MBB.end(), DebugLoc(), get(Opc))
|
|
|
|
.add(Call->getOperand(FuncOp));
|
|
|
|
if (isThumb && !Call->getOperand(FuncOp).isReg())
|
|
|
|
MIB.add(predOps(ARMCC::AL));
|
|
|
|
Call->eraseFromParent();
|
2020-06-11 08:45:46 +02:00
|
|
|
return;
|
2020-05-15 08:44:23 +02:00
|
|
|
}
|
2020-06-11 08:45:46 +02:00
|
|
|
|
|
|
|
// Here we have to insert the return ourselves. Get the correct opcode from
|
|
|
|
// current feature set.
|
|
|
|
BuildMI(MBB, MBB.end(), DebugLoc(), get(Subtarget.getReturnOpcode()))
|
|
|
|
.add(predOps(ARMCC::AL));
|
2020-05-15 08:44:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
MachineBasicBlock::iterator ARMBaseInstrInfo::insertOutlinedCall(
|
|
|
|
Module &M, MachineBasicBlock &MBB, MachineBasicBlock::iterator &It,
|
|
|
|
MachineFunction &MF, const outliner::Candidate &C) const {
|
|
|
|
MachineInstrBuilder MIB;
|
|
|
|
MachineBasicBlock::iterator CallPt;
|
|
|
|
unsigned Opc;
|
|
|
|
bool isThumb = Subtarget.isThumb();
|
|
|
|
|
|
|
|
// Are we tail calling?
|
|
|
|
if (C.CallConstructionID == MachineOutlinerTailCall) {
|
|
|
|
// If yes, then we can just branch to the label.
|
|
|
|
Opc = isThumb
|
|
|
|
? Subtarget.isTargetMachO() ? ARM::tTAILJMPd : ARM::tTAILJMPdND
|
|
|
|
: ARM::TAILJMPd;
|
|
|
|
MIB = BuildMI(MF, DebugLoc(), get(Opc))
|
|
|
|
.addGlobalAddress(M.getNamedValue(MF.getName()));
|
|
|
|
if (isThumb)
|
|
|
|
MIB.add(predOps(ARMCC::AL));
|
|
|
|
It = MBB.insert(It, MIB);
|
|
|
|
return It;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create the call instruction.
|
|
|
|
Opc = isThumb ? ARM::tBL : ARM::BL;
|
|
|
|
MachineInstrBuilder CallMIB = BuildMI(MF, DebugLoc(), get(Opc));
|
|
|
|
if (isThumb)
|
|
|
|
CallMIB.add(predOps(ARMCC::AL));
|
|
|
|
CallMIB.addGlobalAddress(M.getNamedValue(MF.getName()));
|
|
|
|
|
2020-06-15 15:22:08 +02:00
|
|
|
// Can we save to a register?
|
|
|
|
if (C.CallConstructionID == MachineOutlinerRegSave) {
|
|
|
|
unsigned Reg = findRegisterToSaveLRTo(C);
|
|
|
|
assert(Reg != 0 && "No callee-saved register available?");
|
|
|
|
|
|
|
|
// Save and restore LR from that register.
|
|
|
|
if (!MBB.isLiveIn(ARM::LR))
|
|
|
|
MBB.addLiveIn(ARM::LR);
|
|
|
|
copyPhysReg(MBB, It, DebugLoc(), Reg, ARM::LR, true);
|
|
|
|
CallPt = MBB.insert(It, CallMIB);
|
|
|
|
copyPhysReg(MBB, It, DebugLoc(), ARM::LR, Reg, true);
|
|
|
|
It--;
|
|
|
|
return CallPt;
|
|
|
|
}
|
2020-05-15 08:44:23 +02:00
|
|
|
// Insert the call.
|
|
|
|
It = MBB.insert(It, CallMIB);
|
|
|
|
return It;
|
|
|
|
}
|