forked from OSchip/llvm-project
[globalisel][legalizerinfo] Add support for legalization based on the MachineMemOperand
Summary: Currently only the memory size is supported but others can be added as needed. narrowScalar for G_LOAD and G_STORE now correctly update the MachineMemOperand and will refuse to legalize atomics since those need more careful expansions to maintain atomicity. Reviewers: ab, aditya_nandakumar, bogner, rtereshin, aemerson, javed.absar Reviewed By: aemerson Subscribers: aemerson, rovka, kristof.beyls, javed.absar, llvm-commits Differential Revision: https://reviews.llvm.org/D45466 llvm-svn: 331071
This commit is contained in:
parent
3a8a56b8b7
commit
27fe8a5011
|
@ -118,6 +118,20 @@ struct LegalityQuery {
|
|||
unsigned Opcode;
|
||||
ArrayRef<LLT> Types;
|
||||
|
||||
struct MemDesc {
|
||||
uint64_t Size;
|
||||
};
|
||||
|
||||
/// Operations which require memory can use this to place requirements on the
|
||||
/// memory type for each MMO.
|
||||
ArrayRef<MemDesc> MMODescrs;
|
||||
|
||||
constexpr LegalityQuery(unsigned Opcode, const ArrayRef<LLT> Types,
|
||||
const ArrayRef<MemDesc> MMODescrs)
|
||||
: Opcode(Opcode), Types(Types), MMODescrs(MMODescrs) {}
|
||||
constexpr LegalityQuery(unsigned Opcode, const ArrayRef<LLT> Types)
|
||||
: LegalityQuery(Opcode, Types, {}) {}
|
||||
|
||||
raw_ostream &print(raw_ostream &OS) const;
|
||||
};
|
||||
|
||||
|
@ -157,6 +171,11 @@ LegalityPredicate typeInSet(unsigned TypeIdx,
|
|||
LegalityPredicate
|
||||
typePairInSet(unsigned TypeIdx0, unsigned TypeIdx1,
|
||||
std::initializer_list<std::pair<LLT, LLT>> TypesInit);
|
||||
/// True iff the given types for the given pair of type indexes is one of the
|
||||
/// specified type pairs.
|
||||
LegalityPredicate typePairAndMemSizeInSet(
|
||||
unsigned TypeIdx0, unsigned TypeIdx1, unsigned MMOIdx,
|
||||
std::initializer_list<std::tuple<LLT, LLT, unsigned>> TypesAndMemSizeInit);
|
||||
/// True iff the specified type index is a scalar.
|
||||
LegalityPredicate isScalar(unsigned TypeIdx);
|
||||
/// True iff the specified type index is a scalar that's narrower than the given
|
||||
|
@ -168,6 +187,8 @@ LegalityPredicate widerThan(unsigned TypeIdx, unsigned Size);
|
|||
/// True iff the specified type index is a scalar whose size is not a power of
|
||||
/// 2.
|
||||
LegalityPredicate sizeNotPow2(unsigned TypeIdx);
|
||||
/// True iff the specified MMO index has a size that is not a power of 2
|
||||
LegalityPredicate memSizeInBytesNotPow2(unsigned MMOIdx);
|
||||
/// True iff the specified type index is a vector whose element count is not a
|
||||
/// power of 2.
|
||||
LegalityPredicate numElementsNotPow2(unsigned TypeIdx);
|
||||
|
@ -322,6 +343,13 @@ public:
|
|||
LegalizeRuleSet &legalFor(std::initializer_list<std::pair<LLT, LLT>> Types) {
|
||||
return actionFor(LegalizeAction::Legal, Types);
|
||||
}
|
||||
/// The instruction is legal when type indexes 0 and 1 along with the memory
|
||||
/// size is any type and size tuple in the given list.
|
||||
LegalizeRuleSet &legalForTypesWithMemSize(
|
||||
std::initializer_list<std::tuple<LLT, LLT, unsigned>> TypesAndMemSize) {
|
||||
return legalIf(LegalityPredicates::typePairAndMemSizeInSet(
|
||||
0, 1, /*MMOIdx*/ 0, TypesAndMemSize));
|
||||
}
|
||||
/// The instruction is legal when type indexes 0 and 1 are both in the given
|
||||
/// list. That is, the type pair is in the cartesian product of the list.
|
||||
LegalizeRuleSet &legalForCartesianProduct(std::initializer_list<LLT> Types) {
|
||||
|
@ -427,6 +455,10 @@ public:
|
|||
LegalizeRuleSet &unsupportedIf(LegalityPredicate Predicate) {
|
||||
return actionIf(LegalizeAction::Unsupported, Predicate);
|
||||
}
|
||||
LegalizeRuleSet &unsupportedIfMemSizeNotPow2() {
|
||||
return actionIf(LegalizeAction::Unsupported,
|
||||
LegalityPredicates::memSizeInBytesNotPow2(0));
|
||||
}
|
||||
|
||||
LegalizeRuleSet &customIf(LegalityPredicate Predicate) {
|
||||
return actionIf(LegalizeAction::Custom, Predicate);
|
||||
|
@ -510,7 +542,7 @@ public:
|
|||
return moreElementsIf(
|
||||
[=](const LegalityQuery &Query) {
|
||||
LLT VecTy = Query.Types[TypeIdx];
|
||||
return VecTy.getElementType() == EltTy &&
|
||||
return VecTy.isVector() && VecTy.getElementType() == EltTy &&
|
||||
VecTy.getNumElements() < MinElements;
|
||||
},
|
||||
[=](const LegalityQuery &Query) {
|
||||
|
@ -525,7 +557,7 @@ public:
|
|||
return fewerElementsIf(
|
||||
[=](const LegalityQuery &Query) {
|
||||
LLT VecTy = Query.Types[TypeIdx];
|
||||
return VecTy.getElementType() == EltTy &&
|
||||
return VecTy.isVector() && VecTy.getElementType() == EltTy &&
|
||||
VecTy.getNumElements() > MaxElements;
|
||||
},
|
||||
[=](const LegalityQuery &Query) {
|
||||
|
|
|
@ -41,6 +41,18 @@ LegalityPredicate LegalityPredicates::typePairInSet(
|
|||
};
|
||||
}
|
||||
|
||||
LegalityPredicate LegalityPredicates::typePairAndMemSizeInSet(
|
||||
unsigned TypeIdx0, unsigned TypeIdx1, unsigned MMOIdx,
|
||||
std::initializer_list<std::tuple<LLT, LLT, unsigned>> TypesAndMemSizeInit) {
|
||||
SmallVector<std::tuple<LLT, LLT, unsigned>, 4> TypesAndMemSize = TypesAndMemSizeInit;
|
||||
return [=](const LegalityQuery &Query) {
|
||||
std::tuple<LLT, LLT, unsigned> Match = {
|
||||
Query.Types[TypeIdx0], Query.Types[TypeIdx1], Query.MMODescrs[MMOIdx].Size};
|
||||
return std::find(TypesAndMemSize.begin(), TypesAndMemSize.end(), Match) !=
|
||||
TypesAndMemSize.end();
|
||||
};
|
||||
}
|
||||
|
||||
LegalityPredicate LegalityPredicates::isScalar(unsigned TypeIdx) {
|
||||
return [=](const LegalityQuery &Query) {
|
||||
return Query.Types[TypeIdx].isScalar();
|
||||
|
@ -70,6 +82,12 @@ LegalityPredicate LegalityPredicates::sizeNotPow2(unsigned TypeIdx) {
|
|||
};
|
||||
}
|
||||
|
||||
LegalityPredicate LegalityPredicates::memSizeInBytesNotPow2(unsigned MMOIdx) {
|
||||
return [=](const LegalityQuery &Query) {
|
||||
return !isPowerOf2_32(Query.MMODescrs[MMOIdx].Size /* In Bytes */);
|
||||
};
|
||||
}
|
||||
|
||||
LegalityPredicate LegalityPredicates::numElementsNotPow2(unsigned TypeIdx) {
|
||||
return [=](const LegalityQuery &Query) {
|
||||
const LLT &QueryTy = Query.Types[TypeIdx];
|
||||
|
|
|
@ -272,8 +272,8 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
|
|||
|
||||
MIRBuilder.setInstr(MI);
|
||||
|
||||
int64_t SizeOp0 = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
|
||||
int64_t NarrowSize = NarrowTy.getSizeInBits();
|
||||
uint64_t SizeOp0 = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
|
||||
uint64_t NarrowSize = NarrowTy.getSizeInBits();
|
||||
|
||||
switch (MI.getOpcode()) {
|
||||
default:
|
||||
|
@ -339,8 +339,8 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
|
|||
extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, SrcRegs);
|
||||
|
||||
unsigned OpReg = MI.getOperand(0).getReg();
|
||||
int64_t OpStart = MI.getOperand(2).getImm();
|
||||
int64_t OpSize = MRI.getType(OpReg).getSizeInBits();
|
||||
uint64_t OpStart = MI.getOperand(2).getImm();
|
||||
uint64_t OpSize = MRI.getType(OpReg).getSizeInBits();
|
||||
for (int i = 0; i < NumParts; ++i) {
|
||||
unsigned SrcStart = i * NarrowSize;
|
||||
|
||||
|
@ -355,7 +355,8 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
|
|||
|
||||
// OpSegStart is where this destination segment would start in OpReg if it
|
||||
// extended infinitely in both directions.
|
||||
int64_t ExtractOffset, SegSize;
|
||||
int64_t ExtractOffset;
|
||||
uint64_t SegSize;
|
||||
if (OpStart < SrcStart) {
|
||||
ExtractOffset = 0;
|
||||
SegSize = std::min(NarrowSize, OpStart + OpSize - SrcStart);
|
||||
|
@ -391,8 +392,8 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
|
|||
extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, SrcRegs);
|
||||
|
||||
unsigned OpReg = MI.getOperand(2).getReg();
|
||||
int64_t OpStart = MI.getOperand(3).getImm();
|
||||
int64_t OpSize = MRI.getType(OpReg).getSizeInBits();
|
||||
uint64_t OpStart = MI.getOperand(3).getImm();
|
||||
uint64_t OpSize = MRI.getType(OpReg).getSizeInBits();
|
||||
for (int i = 0; i < NumParts; ++i) {
|
||||
unsigned DstStart = i * NarrowSize;
|
||||
|
||||
|
@ -409,7 +410,8 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
|
|||
|
||||
// OpSegStart is where this destination segment would start in OpReg if it
|
||||
// extended infinitely in both directions.
|
||||
int64_t ExtractOffset, InsertOffset, SegSize;
|
||||
int64_t ExtractOffset, InsertOffset;
|
||||
uint64_t SegSize;
|
||||
if (OpStart < DstStart) {
|
||||
InsertOffset = 0;
|
||||
ExtractOffset = DstStart - OpStart;
|
||||
|
@ -443,6 +445,14 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
|
|||
// NarrowSize.
|
||||
if (SizeOp0 % NarrowSize != 0)
|
||||
return UnableToLegalize;
|
||||
|
||||
const auto &MMO = **MI.memoperands_begin();
|
||||
// This implementation doesn't work for atomics. Give up instead of doing
|
||||
// something invalid.
|
||||
if (MMO.getOrdering() != AtomicOrdering::NotAtomic ||
|
||||
MMO.getFailureOrdering() != AtomicOrdering::NotAtomic)
|
||||
return UnableToLegalize;
|
||||
|
||||
int NumParts = SizeOp0 / NarrowSize;
|
||||
LLT OffsetTy = LLT::scalar(
|
||||
MRI.getType(MI.getOperand(1).getReg()).getScalarSizeInBits());
|
||||
|
@ -453,12 +463,16 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
|
|||
unsigned SrcReg = 0;
|
||||
unsigned Adjustment = i * NarrowSize / 8;
|
||||
|
||||
MachineMemOperand *SplitMMO = MIRBuilder.getMF().getMachineMemOperand(
|
||||
MMO.getPointerInfo().getWithOffset(Adjustment), MMO.getFlags(),
|
||||
NarrowSize / 8, i == 0 ? MMO.getAlignment() : NarrowSize / 8,
|
||||
MMO.getAAInfo(), MMO.getRanges(), MMO.getSyncScopeID(),
|
||||
MMO.getOrdering(), MMO.getFailureOrdering());
|
||||
|
||||
MIRBuilder.materializeGEP(SrcReg, MI.getOperand(1).getReg(), OffsetTy,
|
||||
Adjustment);
|
||||
|
||||
// TODO: This is conservatively correct, but we probably want to split the
|
||||
// memory operands in the future.
|
||||
MIRBuilder.buildLoad(DstReg, SrcReg, **MI.memoperands_begin());
|
||||
MIRBuilder.buildLoad(DstReg, SrcReg, *SplitMMO);
|
||||
|
||||
DstRegs.push_back(DstReg);
|
||||
}
|
||||
|
@ -472,6 +486,14 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
|
|||
// NarrowSize.
|
||||
if (SizeOp0 % NarrowSize != 0)
|
||||
return UnableToLegalize;
|
||||
|
||||
const auto &MMO = **MI.memoperands_begin();
|
||||
// This implementation doesn't work for atomics. Give up instead of doing
|
||||
// something invalid.
|
||||
if (MMO.getOrdering() != AtomicOrdering::NotAtomic ||
|
||||
MMO.getFailureOrdering() != AtomicOrdering::NotAtomic)
|
||||
return UnableToLegalize;
|
||||
|
||||
int NumParts = SizeOp0 / NarrowSize;
|
||||
LLT OffsetTy = LLT::scalar(
|
||||
MRI.getType(MI.getOperand(1).getReg()).getScalarSizeInBits());
|
||||
|
@ -483,12 +505,16 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
|
|||
unsigned DstReg = 0;
|
||||
unsigned Adjustment = i * NarrowSize / 8;
|
||||
|
||||
MachineMemOperand *SplitMMO = MIRBuilder.getMF().getMachineMemOperand(
|
||||
MMO.getPointerInfo().getWithOffset(Adjustment), MMO.getFlags(),
|
||||
NarrowSize / 8, i == 0 ? MMO.getAlignment() : NarrowSize / 8,
|
||||
MMO.getAAInfo(), MMO.getRanges(), MMO.getSyncScopeID(),
|
||||
MMO.getOrdering(), MMO.getFailureOrdering());
|
||||
|
||||
MIRBuilder.materializeGEP(DstReg, MI.getOperand(1).getReg(), OffsetTy,
|
||||
Adjustment);
|
||||
|
||||
// TODO: This is conservatively correct, but we probably want to split the
|
||||
// memory operands in the future.
|
||||
MIRBuilder.buildStore(SrcRegs[i], DstReg, **MI.memoperands_begin());
|
||||
MIRBuilder.buildStore(SrcRegs[i], DstReg, *SplitMMO);
|
||||
}
|
||||
MI.eraseFromParent();
|
||||
return Legalized;
|
||||
|
|
|
@ -42,11 +42,18 @@ cl::opt<bool> llvm::DisableGISelLegalityCheck(
|
|||
cl::Hidden);
|
||||
|
||||
raw_ostream &LegalityQuery::print(raw_ostream &OS) const {
|
||||
OS << Opcode << ", {";
|
||||
OS << Opcode << ", Tys={";
|
||||
for (const auto &Type : Types) {
|
||||
OS << Type << ", ";
|
||||
}
|
||||
OS << "}, Opcode=";
|
||||
|
||||
OS << Opcode << ", MMOs={";
|
||||
for (const auto &MMODescr : MMODescrs) {
|
||||
OS << MMODescr.Size << ", ";
|
||||
}
|
||||
OS << "}";
|
||||
|
||||
return OS;
|
||||
}
|
||||
|
||||
|
@ -330,7 +337,12 @@ LegalizerInfo::getAction(const MachineInstr &MI,
|
|||
LLT Ty = getTypeFromTypeIdx(MI, MRI, i, TypeIdx);
|
||||
Types.push_back(Ty);
|
||||
}
|
||||
return getAction({MI.getOpcode(), Types});
|
||||
|
||||
SmallVector<LegalityQuery::MemDesc, 2> MemDescrs;
|
||||
for (const auto &MMO : MI.memoperands())
|
||||
MemDescrs.push_back({MMO->getSize() /* in bytes */ * 8});
|
||||
|
||||
return getAction({MI.getOpcode(), Types, MemDescrs});
|
||||
}
|
||||
|
||||
bool LegalizerInfo::isLegal(const MachineInstr &MI,
|
||||
|
|
|
@ -136,8 +136,15 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST) {
|
|||
.widenScalarToNextPow2(0);
|
||||
|
||||
getActionDefinitionsBuilder({G_LOAD, G_STORE})
|
||||
.legalFor(
|
||||
{{s8, p0}, {s16, p0}, {s32, p0}, {s64, p0}, {p0, p0}, {v2s32, p0}})
|
||||
.legalForTypesWithMemSize({{s8, p0, 8},
|
||||
{s16, p0, 16},
|
||||
{s32, p0, 32},
|
||||
{s64, p0, 64},
|
||||
{p0, p0, 64},
|
||||
{v2s32, p0, 64}})
|
||||
// TODO: We could support sum-of-pow2's but the lowering code doesn't know
|
||||
// how to do that yet.
|
||||
.unsupportedIfMemSizeNotPow2()
|
||||
.clampScalar(0, s8, s64)
|
||||
.widenScalarToNextPow2(0)
|
||||
.clampNumElements(0, v2s32, v2s32);
|
||||
|
|
|
@ -12,10 +12,10 @@ body: |
|
|||
|
||||
; CHECK-LABEL: name: test_extracts_1
|
||||
; CHECK: [[COPY:%[0-9]+]]:_(p0) = COPY $x2
|
||||
; CHECK: [[LOAD:%[0-9]+]]:_(s64) = G_LOAD [[COPY]](p0) :: (load 16)
|
||||
; CHECK: [[LOAD:%[0-9]+]]:_(s64) = G_LOAD [[COPY]](p0) :: (load 8, align 16)
|
||||
; CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 8
|
||||
; CHECK: [[GEP:%[0-9]+]]:_(p0) = G_GEP [[COPY]], [[C]](s64)
|
||||
; CHECK: [[LOAD1:%[0-9]+]]:_(s64) = G_LOAD [[GEP]](p0) :: (load 16)
|
||||
; CHECK: [[LOAD1:%[0-9]+]]:_(s64) = G_LOAD [[GEP]](p0) :: (load 8)
|
||||
; CHECK: [[COPY1:%[0-9]+]]:_(s64) = COPY [[LOAD]](s64)
|
||||
; CHECK: G_STORE [[COPY1]](s64), [[COPY]](p0) :: (store 8)
|
||||
; CHECK: RET_ReallyLR
|
||||
|
@ -37,10 +37,10 @@ body: |
|
|||
; Low extraction wipes takes whole low register. High extraction is real.
|
||||
; CHECK-LABEL: name: test_extracts_2
|
||||
; CHECK: [[COPY:%[0-9]+]]:_(p0) = COPY $x2
|
||||
; CHECK: [[LOAD:%[0-9]+]]:_(s64) = G_LOAD [[COPY]](p0) :: (load 16)
|
||||
; CHECK: [[LOAD:%[0-9]+]]:_(s64) = G_LOAD [[COPY]](p0) :: (load 8, align 16)
|
||||
; CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 8
|
||||
; CHECK: [[GEP:%[0-9]+]]:_(p0) = G_GEP [[COPY]], [[C]](s64)
|
||||
; CHECK: [[LOAD1:%[0-9]+]]:_(s64) = G_LOAD [[GEP]](p0) :: (load 16)
|
||||
; CHECK: [[LOAD1:%[0-9]+]]:_(s64) = G_LOAD [[GEP]](p0) :: (load 8)
|
||||
; CHECK: [[COPY1:%[0-9]+]]:_(s64) = COPY [[LOAD]](s64)
|
||||
; CHECK: [[EXTRACT:%[0-9]+]]:_(s32) = G_EXTRACT [[LOAD1]](s64), 0
|
||||
; CHECK: [[COPY2:%[0-9]+]]:_(s32) = COPY [[EXTRACT]](s32)
|
||||
|
|
|
@ -62,10 +62,10 @@ body: |
|
|||
%13:_(s64) = G_BITCAST %7
|
||||
$x0 = COPY %13
|
||||
|
||||
; CHECK: [[LOAD0:%[0-9]+]]:_(s64) = G_LOAD %0(p0) :: (load 16 from %ir.addr)
|
||||
; CHECK: [[LOAD0:%[0-9]+]]:_(s64) = G_LOAD %0(p0) :: (load 8 from %ir.addr, align 16)
|
||||
; CHECK: [[OFFSET1:%[0-9]+]]:_(s64) = G_CONSTANT i64 8
|
||||
; CHECK: [[GEP1:%[0-9]+]]:_(p0) = G_GEP %0, [[OFFSET1]](s64)
|
||||
; CHECK: [[LOAD1:%[0-9]+]]:_(s64) = G_LOAD [[GEP1]](p0) :: (load 16 from %ir.addr)
|
||||
; CHECK: [[LOAD1:%[0-9]+]]:_(s64) = G_LOAD [[GEP1]](p0) :: (load 8 from %ir.addr + 8)
|
||||
; CHECK: %8:_(s128) = G_MERGE_VALUES [[LOAD0]](s64), [[LOAD1]](s64)
|
||||
%8(s128) = G_LOAD %0(p0) :: (load 16 from %ir.addr)
|
||||
%14:_(s64) = G_TRUNC %8
|
||||
|
@ -120,10 +120,10 @@ body: |
|
|||
; CHECK: G_STORE %0(p0), %0(p0) :: (store 8 into %ir.addr)
|
||||
G_STORE %0(p0), %0(p0) :: (store 8 into %ir.addr)
|
||||
|
||||
; CHECK: G_STORE %5(s64), %0(p0) :: (store 16 into %ir.addr)
|
||||
; CHECK: G_STORE %5(s64), %0(p0) :: (store 8 into %ir.addr, align 16)
|
||||
; CHECK: [[OFFSET1:%[0-9]+]]:_(s64) = G_CONSTANT i64 8
|
||||
; CHECK: [[GEP1:%[0-9]+]]:_(p0) = G_GEP %0, [[OFFSET1]](s64)
|
||||
; CHECK: G_STORE %6(s64), [[GEP1]](p0) :: (store 16 into %ir.addr)
|
||||
; CHECK: G_STORE %6(s64), [[GEP1]](p0) :: (store 8 into %ir.addr + 8)
|
||||
%6(s64) = G_PTRTOINT %0(p0)
|
||||
%7(s128) = G_MERGE_VALUES %5, %6
|
||||
G_STORE %7, %0 :: (store 16 into %ir.addr)
|
||||
|
|
|
@ -95,10 +95,12 @@ body: |
|
|||
; SOFT-ABI: [[SP1:%[0-9]+]]:_(p0) = COPY $sp
|
||||
; SOFT-ABI: [[OFF1:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
|
||||
; SOFT-ABI: [[FI1:%[0-9]+]]:_(p0) = G_GEP [[SP1]], [[OFF1]](s32)
|
||||
; SOFT-ABI: G_STORE [[Y0]](s32), [[FI1]](p0){{.*}}store 8 into stack
|
||||
|
||||
; FIXME: This ought to be align 8 but ARM's call lowering hardcodes it to 0
|
||||
; SOFT-ABI: G_STORE [[Y0]](s32), [[FI1]](p0){{.*}}store 4 into stack, align 0)
|
||||
; SOFT-ABI: [[OFF2:%[0-9]+]]:_(s32) = G_CONSTANT i32 4
|
||||
; SOFT-ABI: [[FI2:%[0-9]+]]:_(p0) = G_GEP [[FI1]], [[OFF2]](s32)
|
||||
; SOFT-ABI: G_STORE [[Y1]](s32), [[FI2]](p0){{.*}}store 8 into stack
|
||||
; SOFT-ABI: G_STORE [[Y1]](s32), [[FI2]](p0){{.*}}store 4 into stack + 4)
|
||||
; SOFT-ABI: BL &fma, {{.*}}, implicit $r0, implicit $r1, implicit $r2, implicit $r3, implicit-def $r0, implicit-def $r1
|
||||
; SOFT-ABI-DAG: [[R0:%[0-9]+]]:_(s32) = COPY $r0
|
||||
; SOFT-ABI-DAG: [[R1:%[0-9]+]]:_(s32) = COPY $r1
|
||||
|
|
|
@ -96,14 +96,14 @@ body: |
|
|||
; X64: G_STORE [[LOAD]](s64), [[DEF]](p0) :: (store 8)
|
||||
; X32-LABEL: name: test_memop_s64
|
||||
; X32: [[DEF:%[0-9]+]]:_(p0) = IMPLICIT_DEF
|
||||
; X32: [[LOAD:%[0-9]+]]:_(s32) = G_LOAD [[DEF]](p0) :: (load 8)
|
||||
; X32: [[LOAD:%[0-9]+]]:_(s32) = G_LOAD [[DEF]](p0) :: (load 4, align 8)
|
||||
; X32: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 4
|
||||
; X32: [[GEP:%[0-9]+]]:_(p0) = G_GEP [[DEF]], [[C]](s32)
|
||||
; X32: [[LOAD1:%[0-9]+]]:_(s32) = G_LOAD [[GEP]](p0) :: (load 8)
|
||||
; X32: G_STORE [[LOAD]](s32), [[DEF]](p0) :: (store 8)
|
||||
; X32: [[LOAD1:%[0-9]+]]:_(s32) = G_LOAD [[GEP]](p0) :: (load 4)
|
||||
; X32: G_STORE [[LOAD]](s32), [[DEF]](p0) :: (store 4, align 8)
|
||||
; X32: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 4
|
||||
; X32: [[GEP1:%[0-9]+]]:_(p0) = G_GEP [[DEF]], [[C1]](s32)
|
||||
; X32: G_STORE [[LOAD1]](s32), [[GEP1]](p0) :: (store 8)
|
||||
; X32: G_STORE [[LOAD1]](s32), [[GEP1]](p0) :: (store 4)
|
||||
%0(p0) = IMPLICIT_DEF
|
||||
%1(s64) = G_LOAD %0(p0) :: (load 8)
|
||||
|
||||
|
|
|
@ -14,38 +14,38 @@ body: |
|
|||
; X64: [[DEF1:%[0-9]+]]:_(s8) = G_IMPLICIT_DEF
|
||||
; X64: G_STORE [[DEF1]](s8), [[DEF]](p0) :: (store 1)
|
||||
; X64: [[DEF2:%[0-9]+]]:_(s8) = G_IMPLICIT_DEF
|
||||
; X64: G_STORE [[DEF2]](s8), [[DEF]](p0) :: (store 8)
|
||||
; X64: G_STORE [[DEF2]](s8), [[DEF]](p0) :: (store 1)
|
||||
; X64: [[DEF3:%[0-9]+]]:_(s16) = G_IMPLICIT_DEF
|
||||
; X64: G_STORE [[DEF3]](s16), [[DEF]](p0) :: (store 16)
|
||||
; X64: G_STORE [[DEF3]](s16), [[DEF]](p0) :: (store 2)
|
||||
; X64: [[DEF4:%[0-9]+]]:_(s32) = G_IMPLICIT_DEF
|
||||
; X64: G_STORE [[DEF4]](s32), [[DEF]](p0) :: (store 32)
|
||||
; X64: G_STORE [[DEF4]](s32), [[DEF]](p0) :: (store 4)
|
||||
; X64: [[DEF5:%[0-9]+]]:_(s64) = G_IMPLICIT_DEF
|
||||
; X64: G_STORE [[DEF5]](s64), [[DEF]](p0) :: (store 64)
|
||||
; X64: G_STORE [[DEF5]](s64), [[DEF]](p0) :: (store 8)
|
||||
; X32-LABEL: name: test_implicit_def
|
||||
; X32: [[DEF:%[0-9]+]]:_(p0) = G_IMPLICIT_DEF
|
||||
; X32: [[DEF1:%[0-9]+]]:_(s8) = G_IMPLICIT_DEF
|
||||
; X32: G_STORE [[DEF1]](s8), [[DEF]](p0) :: (store 1)
|
||||
; X32: [[DEF2:%[0-9]+]]:_(s8) = G_IMPLICIT_DEF
|
||||
; X32: G_STORE [[DEF2]](s8), [[DEF]](p0) :: (store 8)
|
||||
; X32: G_STORE [[DEF2]](s8), [[DEF]](p0) :: (store 1)
|
||||
; X32: [[DEF3:%[0-9]+]]:_(s16) = G_IMPLICIT_DEF
|
||||
; X32: G_STORE [[DEF3]](s16), [[DEF]](p0) :: (store 16)
|
||||
; X32: G_STORE [[DEF3]](s16), [[DEF]](p0) :: (store 2)
|
||||
; X32: [[DEF4:%[0-9]+]]:_(s32) = G_IMPLICIT_DEF
|
||||
; X32: G_STORE [[DEF4]](s32), [[DEF]](p0) :: (store 32)
|
||||
; X32: G_STORE [[DEF4]](s32), [[DEF]](p0) :: (store 4)
|
||||
; X32: [[DEF5:%[0-9]+]]:_(s32) = G_IMPLICIT_DEF
|
||||
; X32: [[DEF6:%[0-9]+]]:_(s32) = G_IMPLICIT_DEF
|
||||
; X32: G_STORE [[DEF5]](s32), [[DEF]](p0) :: (store 64)
|
||||
; X32: G_STORE [[DEF5]](s32), [[DEF]](p0) :: (store 4, align 8)
|
||||
; X32: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 4
|
||||
; X32: [[GEP:%[0-9]+]]:_(p0) = G_GEP [[DEF]], [[C]](s32)
|
||||
; X32: G_STORE [[DEF6]](s32), [[GEP]](p0) :: (store 64)
|
||||
; X32: G_STORE [[DEF6]](s32), [[GEP]](p0) :: (store 4)
|
||||
%5:_(p0) = G_IMPLICIT_DEF
|
||||
%0:_(s1) = G_IMPLICIT_DEF
|
||||
G_STORE %0, %5 ::(store 1)
|
||||
%1:_(s8) = G_IMPLICIT_DEF
|
||||
G_STORE %1, %5 ::(store 8)
|
||||
G_STORE %1, %5 ::(store 1)
|
||||
%2:_(s16) = G_IMPLICIT_DEF
|
||||
G_STORE %2, %5 ::(store 16)
|
||||
G_STORE %2, %5 ::(store 2)
|
||||
%3:_(s32) = G_IMPLICIT_DEF
|
||||
G_STORE %3, %5 ::(store 32)
|
||||
G_STORE %3, %5 ::(store 4)
|
||||
%4:_(s64) = G_IMPLICIT_DEF
|
||||
G_STORE %4, %5 ::(store 64)
|
||||
G_STORE %4, %5 ::(store 8)
|
||||
...
|
||||
|
|
Loading…
Reference in New Issue