[GlobalISel] Emit opt remarks on isel fallbacks.

Having more fine-grained information on the specific construct that
caused us to fallback is valuable for large-scale data collection.

We still have the fallback warning, that's also used for FastISel.
We still need to remove the fallback warning, and teach FastISel to also
emit remarks (it currently has a combination of the warning, stats, and
debug prints: the remarks could unify all three).

The abort-on-fallback path could also be better handled using remarks:
one could imagine a "-Rpass-error", analoguous to "-Werror", which would
promote missed/failed remarks to errors.  It's not clear whether that
would be useful for other remarks though, so we're not there yet.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@296013 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Ahmed Bougacha 2017-02-23 21:05:42 +00:00
parent 75fdc3a2ae
commit 65d76e1285
9 changed files with 146 additions and 83 deletions

View File

@ -34,6 +34,7 @@ class Instruction;
class MachineBasicBlock;
class MachineFunction;
class MachineInstr;
class OptimizationRemarkEmitter;
class MachineRegisterInfo;
class TargetPassConfig;
@ -373,6 +374,9 @@ private:
/// Current target configuration. Controls how the pass handles errors.
const TargetPassConfig *TPC;
/// Current optimization remark emitter. Used to report failures.
std::unique_ptr<OptimizationRemarkEmitter> ORE;
// * Insert all the code needed to materialize the constants
// at the proper place. E.g., Entry block or dominator block
// of each constant depending on how fancy we want to be.

View File

@ -67,6 +67,7 @@
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
#include "llvm/CodeGen/GlobalISel/RegisterBankInfo.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
namespace llvm {
// Forward declarations.
@ -484,6 +485,9 @@ private:
/// This is required for non-fast mode.
MachineBranchProbabilityInfo *MBPI;
/// Current optimization remark emitter. Used to report failures.
std::unique_ptr<MachineOptimizationRemarkEmitter> MORE;
/// Helper class used for every code morphing.
MachineIRBuilder MIRBuilder;

View File

@ -15,15 +15,21 @@
#ifndef LLVM_CODEGEN_GLOBALISEL_UTILS_H
#define LLVM_CODEGEN_GLOBALISEL_UTILS_H
#include "llvm/ADT/StringRef.h"
namespace llvm {
class MachineFunction;
class MachineInstr;
class MachineOptimizationRemarkEmitter;
class MachineOptimizationRemarkMissed;
class MachineRegisterInfo;
class MCInstrDesc;
class RegisterBankInfo;
class TargetInstrInfo;
class TargetPassConfig;
class TargetRegisterInfo;
class Twine;
/// Try to constrain Reg so that it is usable by argument OpIdx of the
/// provided MCInstrDesc \p II. If this fails, create a new virtual
@ -39,5 +45,16 @@ unsigned constrainOperandRegClass(const MachineFunction &MF,
MachineInstr &InsertPt, const MCInstrDesc &II,
unsigned Reg, unsigned OpIdx);
/// Report an ISel error as a missed optimization remark to the LLVMContext's
/// diagnostic stream. Set the FailedISel MachineFunction property.
void reportGISelFailure(MachineFunction &MF, const TargetPassConfig &TPC,
MachineOptimizationRemarkEmitter &MORE,
MachineOptimizationRemarkMissed &R);
void reportGISelFailure(MachineFunction &MF, const TargetPassConfig &TPC,
MachineOptimizationRemarkEmitter &MORE,
const char *PassName, StringRef Msg,
const MachineInstr &MI);
} // End namespace llvm.
#endif

View File

@ -14,6 +14,7 @@
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Analysis/OptimizationDiagnosticInfo.h"
#include "llvm/CodeGen/GlobalISel/CallLowering.h"
#include "llvm/CodeGen/Analysis.h"
#include "llvm/CodeGen/MachineFunction.h"
@ -43,11 +44,21 @@ INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
INITIALIZE_PASS_END(IRTranslator, DEBUG_TYPE, "IRTranslator LLVM IR -> MI",
false, false)
static void reportTranslationError(const Value &V, const Twine &Message) {
std::string ErrStorage;
raw_string_ostream Err(ErrStorage);
Err << Message << ": " << V << '\n';
report_fatal_error(Err.str());
static void reportTranslationError(MachineFunction &MF,
const TargetPassConfig &TPC,
OptimizationRemarkEmitter &ORE,
OptimizationRemarkMissed &R) {
MF.getProperties().set(MachineFunctionProperties::Property::FailedISel);
// Print the function name explicitly if we don't have a debug location (which
// makes the diagnostic less useful) or if we're going to emit a raw error.
if (!R.getLocation().isValid() || TPC.isGlobalISelAbortEnabled())
R << (" (in function: " + MF.getName() + ")").str();
if (TPC.isGlobalISelAbortEnabled())
report_fatal_error(R.getMsg());
else
ORE.emit(R);
}
IRTranslator::IRTranslator() : MachineFunctionPass(ID), MRI(nullptr) {
@ -76,12 +87,12 @@ unsigned IRTranslator::getOrCreateVReg(const Value &Val) {
if (auto CV = dyn_cast<Constant>(&Val)) {
bool Success = translate(*CV, VReg);
if (!Success) {
if (!TPC->isGlobalISelAbortEnabled()) {
MF->getProperties().set(
MachineFunctionProperties::Property::FailedISel);
return VReg;
}
reportTranslationError(Val, "unable to translate constant");
OptimizationRemarkMissed R("gisel-irtranslator", "GISelFailure",
DebugLoc(),
&MF->getFunction()->getEntryBlock());
R << "unable to translate constant: " << ore::NV("Type", Val.getType());
reportTranslationError(*MF, *TPC, *ORE, R);
return VReg;
}
}
@ -117,12 +128,12 @@ unsigned IRTranslator::getMemOpAlignment(const Instruction &I) {
} else if (const LoadInst *LI = dyn_cast<LoadInst>(&I)) {
Alignment = LI->getAlignment();
ValTy = LI->getType();
} else if (!TPC->isGlobalISelAbortEnabled()) {
MF->getProperties().set(
MachineFunctionProperties::Property::FailedISel);
} else {
OptimizationRemarkMissed R("gisel-irtranslator", "", &I);
R << "unable to translate memop: " << ore::NV("Opcode", &I);
reportTranslationError(*MF, *TPC, *ORE, R);
return 1;
} else
llvm_unreachable("unhandled memory instruction");
}
return Alignment ? Alignment : DL->getABITypeAlignment(ValTy);
}
@ -1018,6 +1029,7 @@ bool IRTranslator::runOnMachineFunction(MachineFunction &CurMF) {
MRI = &MF->getRegInfo();
DL = &F.getParent()->getDataLayout();
TPC = &getAnalysis<TargetPassConfig>();
ORE = make_unique<OptimizationRemarkEmitter>(&F);
assert(PendingPHIs.empty() && "stale PHIs");
@ -1034,13 +1046,12 @@ bool IRTranslator::runOnMachineFunction(MachineFunction &CurMF) {
VRegArgs.push_back(getOrCreateVReg(Arg));
bool Succeeded = CLI->lowerFormalArguments(EntryBuilder, F, VRegArgs);
if (!Succeeded) {
if (!TPC->isGlobalISelAbortEnabled()) {
MF->getProperties().set(
MachineFunctionProperties::Property::FailedISel);
finalizeFunction();
return false;
}
report_fatal_error("Unable to lower arguments");
OptimizationRemarkMissed R("gisel-irtranslator", "GISelFailure", DebugLoc(),
&MF->getFunction()->getEntryBlock());
R << "unable to lower arguments: " << ore::NV("Prototype", F.getType());
reportTranslationError(*MF, *TPC, *ORE, R);
finalizeFunction();
return false;
}
// And translate the function!
@ -1053,10 +1064,15 @@ bool IRTranslator::runOnMachineFunction(MachineFunction &CurMF) {
for (const Instruction &Inst: BB) {
Succeeded &= translate(Inst);
if (!Succeeded) {
if (TPC->isGlobalISelAbortEnabled())
reportTranslationError(Inst, "unable to translate instruction");
MF->getProperties().set(
MachineFunctionProperties::Property::FailedISel);
std::string InstStrStorage;
raw_string_ostream InstStr(InstStrStorage);
InstStr << Inst;
OptimizationRemarkMissed R("gisel-irtranslator", "IRTranslatorFailure: ",
&Inst);
R << "unable to translate instruction: " << ore::NV("Opcode", &Inst)
<< ": '" << InstStr.str() << "'";
reportTranslationError(*MF, *TPC, *ORE, R);
break;
}
}

View File

@ -16,6 +16,8 @@
#include "llvm/ADT/Twine.h"
#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
#include "llvm/CodeGen/GlobalISel/Utils.h"
#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/TargetPassConfig.h"
#include "llvm/IR/Function.h"
@ -45,16 +47,6 @@ void InstructionSelect::getAnalysisUsage(AnalysisUsage &AU) const {
MachineFunctionPass::getAnalysisUsage(AU);
}
static void reportSelectionError(const MachineFunction &MF,
const MachineInstr *MI, const Twine &Message) {
std::string ErrStorage;
raw_string_ostream Err(ErrStorage);
Err << Message << ":\nIn function: " << MF.getName() << '\n';
if (MI)
Err << *MI << '\n';
report_fatal_error(Err.str());
}
bool InstructionSelect::runOnMachineFunction(MachineFunction &MF) {
const MachineRegisterInfo &MRI = MF.getRegInfo();
@ -74,6 +66,9 @@ bool InstructionSelect::runOnMachineFunction(MachineFunction &MF) {
const InstructionSelector *ISel = MF.getSubtarget().getInstructionSelector();
assert(ISel && "Cannot work without InstructionSelector");
// An optimization remark emitter. Used to report failures.
MachineOptimizationRemarkEmitter MORE(MF, /*MBFI=*/nullptr);
// FIXME: freezeReservedRegs is now done in IRTranslator, but there are many
// other MF/MFI fields we need to initialize.
@ -86,10 +81,13 @@ bool InstructionSelect::runOnMachineFunction(MachineFunction &MF) {
// that it has the same layering problem, but we only use inline methods so
// end up not needing to link against the GlobalISel library.
if (const LegalizerInfo *MLI = MF.getSubtarget().getLegalizerInfo())
for (const MachineBasicBlock &MBB : MF)
for (const MachineInstr &MI : MBB)
if (isPreISelGenericOpcode(MI.getOpcode()) && !MLI->isLegal(MI, MRI))
reportSelectionError(MF, &MI, "Instruction is not legal");
for (MachineBasicBlock &MBB : MF)
for (MachineInstr &MI : MBB)
if (isPreISelGenericOpcode(MI.getOpcode()) && !MLI->isLegal(MI, MRI)) {
reportGISelFailure(MF, TPC, MORE, "gisel-select",
"instruction is not legal", MI);
return false;
}
#endif
// FIXME: We could introduce new blocks and will need to fix the outer loop.
@ -121,11 +119,9 @@ bool InstructionSelect::runOnMachineFunction(MachineFunction &MF) {
DEBUG(dbgs() << "Selecting: \n " << MI);
if (!ISel->select(MI)) {
if (TPC.isGlobalISelAbortEnabled())
// FIXME: It would be nice to dump all inserted instructions. It's
// not obvious how, esp. considering select() can insert after MI.
reportSelectionError(MF, &MI, "Cannot select");
MF.getProperties().set(MachineFunctionProperties::Property::FailedISel);
// FIXME: It would be nice to dump all inserted instructions. It's
// not obvious how, esp. considering select() can insert after MI.
reportGISelFailure(MF, TPC, MORE, "gisel-select", "cannot select", MI);
return false;
}
@ -153,28 +149,26 @@ bool InstructionSelect::runOnMachineFunction(MachineFunction &MF) {
MI = &*MRI.use_instr_begin(VReg);
if (MI && !RC) {
if (TPC.isGlobalISelAbortEnabled())
reportSelectionError(MF, MI, "VReg has no regclass after selection");
MF.getProperties().set(MachineFunctionProperties::Property::FailedISel);
reportGISelFailure(MF, TPC, MORE, "gisel-select",
"VReg has no regclass after selection", *MI);
return false;
} else if (!RC)
continue;
if (VRegToType.second.isValid() &&
VRegToType.second.getSizeInBits() > (RC->getSize() * 8)) {
if (TPC.isGlobalISelAbortEnabled())
reportSelectionError(
MF, MI, "VReg has explicit size different from class size");
MF.getProperties().set(MachineFunctionProperties::Property::FailedISel);
reportGISelFailure(MF, TPC, MORE, "gisel-select",
"VReg has explicit size different from class size",
*MI);
return false;
}
}
if (MF.size() != NumBlocks) {
if (TPC.isGlobalISelAbortEnabled())
reportSelectionError(MF, /*MI=*/nullptr,
"Inserting blocks is not supported yet");
MF.getProperties().set(MachineFunctionProperties::Property::FailedISel);
MachineOptimizationRemarkMissed R("gisel-select", "GISelFailure",
DebugLoc(), /*MBB=*/nullptr);
R << "inserting blocks is not supported yet";
reportGISelFailure(MF, TPC, MORE, R);
return false;
}

View File

@ -16,6 +16,8 @@
#include "llvm/CodeGen/GlobalISel/Legalizer.h"
#include "llvm/CodeGen/GlobalISel/LegalizerHelper.h"
#include "llvm/CodeGen/GlobalISel/Legalizer.h"
#include "llvm/CodeGen/GlobalISel/Utils.h"
#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/TargetPassConfig.h"
#include "llvm/Support/Debug.h"
@ -123,6 +125,7 @@ bool Legalizer::runOnMachineFunction(MachineFunction &MF) {
init(MF);
const TargetPassConfig &TPC = getAnalysis<TargetPassConfig>();
const LegalizerInfo &LegalizerInfo = *MF.getSubtarget().getLegalizerInfo();
MachineOptimizationRemarkEmitter MORE(MF, /*MBFI=*/nullptr);
LegalizerHelper Helper(MF);
// FIXME: an instruction may need more than one pass before it is legal. For
@ -148,16 +151,9 @@ bool Legalizer::runOnMachineFunction(MachineFunction &MF) {
// Error out if we couldn't legalize this instruction. We may want to fall
// back to DAG ISel instead in the future.
if (Res == LegalizerHelper::UnableToLegalize) {
if (!TPC.isGlobalISelAbortEnabled()) {
MF.getProperties().set(
MachineFunctionProperties::Property::FailedISel);
return false;
}
std::string Msg;
raw_string_ostream OS(Msg);
OS << "unable to legalize instruction: ";
MI->print(OS);
report_fatal_error(OS.str());
reportGISelFailure(MF, TPC, MORE, "gisel-legalize",
"unable to legalize instruction", *MI);
return false;
}
Changed |= Res == LegalizerHelper::Legalized;

View File

@ -14,6 +14,7 @@
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
#include "llvm/CodeGen/GlobalISel/RegisterBank.h"
#include "llvm/CodeGen/GlobalISel/Utils.h"
#include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
#include "llvm/CodeGen/MachineBranchProbabilityInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
@ -71,6 +72,7 @@ void RegBankSelect::init(MachineFunction &MF) {
MBPI = nullptr;
}
MIRBuilder.setMF(MF);
MORE = make_unique<MachineOptimizationRemarkEmitter>(MF, MBFI);
}
void RegBankSelect::getAnalysisUsage(AnalysisUsage &AU) const {
@ -585,18 +587,12 @@ bool RegBankSelect::runOnMachineFunction(MachineFunction &MF) {
// LegalizerInfo as it's currently in the separate GlobalISel library.
const MachineRegisterInfo &MRI = MF.getRegInfo();
if (const LegalizerInfo *MLI = MF.getSubtarget().getLegalizerInfo()) {
for (const MachineBasicBlock &MBB : MF) {
for (const MachineInstr &MI : MBB) {
for (MachineBasicBlock &MBB : MF) {
for (MachineInstr &MI : MBB) {
if (isPreISelGenericOpcode(MI.getOpcode()) && !MLI->isLegal(MI, MRI)) {
if (!TPC->isGlobalISelAbortEnabled()) {
MF.getProperties().set(
MachineFunctionProperties::Property::FailedISel);
return false;
}
std::string ErrStorage;
raw_string_ostream Err(ErrStorage);
Err << "Instruction is not legal: " << MI << '\n';
report_fatal_error(Err.str());
reportGISelFailure(MF, *TPC, *MORE, "gisel-regbankselect",
"instruction is not legal", MI);
return false;
}
}
}
@ -622,9 +618,8 @@ bool RegBankSelect::runOnMachineFunction(MachineFunction &MF) {
continue;
if (!assignInstr(MI)) {
if (TPC->isGlobalISelAbortEnabled())
report_fatal_error("Unable to map instruction");
MF.getProperties().set(MachineFunctionProperties::Property::FailedISel);
reportGISelFailure(MF, *TPC, *MORE, "gisel-regbankselect",
"unable to map instruction", MI);
return false;
}
}

View File

@ -11,10 +11,13 @@
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/GlobalISel/Utils.h"
#include "llvm/ADT/Twine.h"
#include "llvm/CodeGen/GlobalISel/RegisterBankInfo.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/TargetPassConfig.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetRegisterInfo.h"
@ -43,3 +46,29 @@ unsigned llvm::constrainOperandRegClass(
return Reg;
}
void llvm::reportGISelFailure(MachineFunction &MF, const TargetPassConfig &TPC,
MachineOptimizationRemarkEmitter &MORE,
MachineOptimizationRemarkMissed &R) {
MF.getProperties().set(MachineFunctionProperties::Property::FailedISel);
// Print the function name explicitly if we don't have a debug location (which
// makes the diagnostic less useful) or if we're going to emit a raw error.
if (!R.getLocation().isValid() || TPC.isGlobalISelAbortEnabled())
R << (" (in function: " + MF.getName() + ")").str();
if (TPC.isGlobalISelAbortEnabled())
report_fatal_error(R.getMsg());
else
MORE.emit(R);
}
void llvm::reportGISelFailure(MachineFunction &MF, const TargetPassConfig &TPC,
MachineOptimizationRemarkEmitter &MORE,
const char *PassName, StringRef Msg,
const MachineInstr &MI) {
MachineOptimizationRemarkMissed R(PassName, "GISelFailure: ",
MI.getDebugLoc(), MI.getParent());
R << Msg << ": " << ore::MNV("Inst", MI);
reportGISelFailure(MF, TPC, MORE, R);
}

View File

@ -1,6 +1,6 @@
; RUN: not llc -O0 -global-isel -verify-machineinstrs %s -o - 2>&1 | FileCheck %s --check-prefix=ERROR
; RUN: llc -O0 -global-isel -global-isel-abort=0 -verify-machineinstrs %s -o - 2>&1 | FileCheck %s --check-prefix=FALLBACK
; RUN: llc -O0 -global-isel -global-isel-abort=2 -verify-machineinstrs %s -o %t.out 2> %t.err
; RUN: llc -O0 -global-isel -global-isel-abort=2 -pass-remarks-missed='gisel*' -verify-machineinstrs %s -o %t.out 2> %t.err
; RUN: FileCheck %s --check-prefix=FALLBACK-WITH-REPORT-OUT < %t.out
; RUN: FileCheck %s --check-prefix=FALLBACK-WITH-REPORT-ERR < %t.err
; This file checks that the fallback path to selection dag works.
@ -14,10 +14,11 @@ target triple = "aarch64--"
; We use __fixunstfti as the common denominator for __fixunstfti on Linux and
; ___fixunstfti on iOS
; ERROR: Unable to lower arguments
; ERROR: unable to lower arguments: i128 (i128)* (in function: ABIi128)
; FALLBACK: ldr q0,
; FALLBACK-NEXT: bl __fixunstfti
;
; FALLBACK-WITH-REPORT-ERR: remark: <unknown>:0:0: unable to lower arguments: i128 (i128)* (in function: ABIi128)
; FALLBACK-WITH-REPORT-ERR: warning: Instruction selection used fallback path for ABIi128
; FALLBACK-WITH-REPORT-OUT-LABEL: ABIi128:
; FALLBACK-WITH-REPORT-OUT: ldr q0,
@ -31,6 +32,7 @@ define i128 @ABIi128(i128 %arg1) {
; It happens that we don't handle ConstantArray instances yet during
; translation. Any other constant would be fine too.
; FALLBACK-WITH-REPORT-ERR: remark: <unknown>:0:0: unable to translate constant: [1 x double] (in function: constant)
; FALLBACK-WITH-REPORT-ERR: warning: Instruction selection used fallback path for constant
; FALLBACK-WITH-REPORT-OUT-LABEL: constant:
; FALLBACK-WITH-REPORT-OUT: fmov d0, #1.0
@ -41,6 +43,7 @@ define [1 x double] @constant() {
; The key problem here is that we may fail to create an MBB referenced by a
; PHI. If so, we cannot complete the G_PHI and mustn't try or bad things
; happen.
; FALLBACK-WITH-REPORT-ERR: remark: <unknown>:0:0: cannot select: G_STORE %vreg4, %vreg2; mem:ST4[%addr] GPR:%vreg4,%vreg2 (in function: pending_phis)
; FALLBACK-WITH-REPORT-ERR: warning: Instruction selection used fallback path for pending_phis
; FALLBACK-WITH-REPORT-OUT-LABEL: pending_phis:
define i32 @pending_phis(i1 %tst, i32 %val, i32* %addr) {
@ -60,6 +63,7 @@ false:
}
; General legalizer inability to handle types whose size wasn't a power of 2.
; FALLBACK-WITH-REPORT-ERR: remark: <unknown>:0:0: unable to legalize instruction: %vreg1<def>(s42) = G_LOAD %vreg0; mem:LD6[%addr](align=8) (in function: odd_type)
; FALLBACK-WITH-REPORT-ERR: warning: Instruction selection used fallback path for odd_type
; FALLBACK-WITH-REPORT-OUT-LABEL: odd_type:
define void @odd_type(i42* %addr) {
@ -69,6 +73,7 @@ define void @odd_type(i42* %addr) {
; RegBankSelect crashed when given invalid mappings, and AArch64's
; implementation produce valid-but-nonsense mappings for G_SEQUENCE.
; FALLBACK-WITH-REPORT-ERR: remark: <unknown>:0:0: unable to map instruction: %vreg0<def>(s128) = G_SEQUENCE %vreg1, 0, %vreg2, 64; GPR:%vreg1,%vreg2 (in function: sequence_mapping)
; FALLBACK-WITH-REPORT-ERR: warning: Instruction selection used fallback path for sequence_mapping
; FALLBACK-WITH-REPORT-OUT-LABEL: sequence_mapping:
define void @sequence_mapping([2 x i64] %in) {
@ -76,6 +81,7 @@ define void @sequence_mapping([2 x i64] %in) {
}
; Legalizer was asserting when it enountered an unexpected default action.
; FALLBACK-WITH-REPORT-ERR: remark: <unknown>:0:0: unable to legalize instruction: %vreg9<def>(s128) = G_INSERT %vreg10, %vreg0, 32; (in function: legal_default)
; FALLBACK-WITH-REPORT-ERR: warning: Instruction selection used fallback path for legal_default
; FALLBACK-WITH-REPORT-LABEL: legal_default:
define void @legal_default([8 x i8] %in) {
@ -85,6 +91,7 @@ define void @legal_default([8 x i8] %in) {
; AArch64 was asserting instead of returning an invalid mapping for unknown
; sizes.
; FALLBACK-WITH-REPORT-ERR: remark: <unknown>:0:0: unable to translate instruction: ret: ' ret i128 undef' (in function: sequence_sizes)
; FALLBACK-WITH-REPORT-ERR: warning: Instruction selection used fallback path for sequence_sizes
; FALLBACK-WITH-REPORT-LABEL: sequence_sizes:
define i128 @sequence_sizes([8 x i8] %in) {
@ -92,6 +99,7 @@ define i128 @sequence_sizes([8 x i8] %in) {
}
; Just to make sure we don't accidentally emit a normal load/store.
; FALLBACK-WITH-REPORT-ERR: remark: <unknown>:0:0: cannot select: %vreg2<def>(s64) = G_LOAD %vreg0; mem:LD8[%addr] GPR:%vreg2,%vreg0 (in function: atomic_ops)
; FALLBACK-WITH-REPORT-ERR: warning: Instruction selection used fallback path for atomic_ops
; FALLBACK-WITH-REPORT-LABEL: atomic_ops:
define i64 @atomic_ops(i64* %addr) {