mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 18:54:02 +01:00
Add support for pointer types in patterns
Summary: This adds support for defining patterns for global isel using pointer types, for example: def : Pat<(load GPR32:$src), (p1 (LOAD GPR32:$src))>; DAGISelEmitter will ignore the pointer information and treat these types as integers with the same bit-width as the pointer type. Reviewers: dsanders, rtereshin, arsenm Reviewed By: arsenm Subscribers: Petar.Avramovic, wdng, rovka, kristof.beyls, jfb, volkan, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D57065 llvm-svn: 354510
This commit is contained in:
parent
26f6736219
commit
f743f61832
@ -166,3 +166,14 @@ def iPTR : ValueType<0 , 254>;
|
|||||||
|
|
||||||
// Pseudo valuetype to represent "any type of any size".
|
// Pseudo valuetype to represent "any type of any size".
|
||||||
def Any : ValueType<0 , 255>;
|
def Any : ValueType<0 , 255>;
|
||||||
|
|
||||||
|
/// This class is for targets that want to use pointer types in patterns
|
||||||
|
/// with the GlobalISelEmitter. Targets must define their own pointer
|
||||||
|
/// derived from this class. The scalar argument should be an
|
||||||
|
/// integer type with the same bit size as the ponter.
|
||||||
|
/// e.g. def p0 : PtrValueType <i64, 0>;
|
||||||
|
|
||||||
|
class PtrValueType <ValueType scalar, int addrspace> :
|
||||||
|
ValueType<scalar.Size, scalar.Value> {
|
||||||
|
int AddrSpace = addrspace;
|
||||||
|
}
|
||||||
|
@ -128,10 +128,12 @@ def HasC : Predicate<"Subtarget->hasC()"> { let RecomputePerFunction = 1; }
|
|||||||
|
|
||||||
// CHECK-LABEL: // LLT Objects.
|
// CHECK-LABEL: // LLT Objects.
|
||||||
// CHECK-NEXT: enum {
|
// CHECK-NEXT: enum {
|
||||||
|
// CHECK-NEXT: GILLT_p0s32
|
||||||
// CHECK-NEXT: GILLT_s32,
|
// CHECK-NEXT: GILLT_s32,
|
||||||
// CHECK-NEXT: }
|
// CHECK-NEXT: }
|
||||||
// CHECK-NEXT: const static size_t NumTypeObjects = 1;
|
// CHECK-NEXT: const static size_t NumTypeObjects = 2;
|
||||||
// CHECK-NEXT: const static LLT TypeObjects[] = {
|
// CHECK-NEXT: const static LLT TypeObjects[] = {
|
||||||
|
// CHECK-NEXT: LLT::pointer(0, 32),
|
||||||
// CHECK-NEXT: LLT::scalar(32),
|
// CHECK-NEXT: LLT::scalar(32),
|
||||||
// CHECK-NEXT: };
|
// CHECK-NEXT: };
|
||||||
|
|
||||||
@ -829,7 +831,7 @@ def : Pat<(not GPR32:$Wm), (ORN R0, GPR32:$Wm)>;
|
|||||||
// NOOPT-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src3
|
// NOOPT-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src3
|
||||||
// NOOPT-NEXT: GIR_EraseFromParent, /*InsnID*/0,
|
// NOOPT-NEXT: GIR_EraseFromParent, /*InsnID*/0,
|
||||||
// NOOPT-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
|
// NOOPT-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
|
||||||
// NOOPT-NEXT: // GIR_Coverage, 25,
|
// NOOPT-NEXT: // GIR_Coverage, 26,
|
||||||
// NOOPT-NEXT: GIR_Done,
|
// NOOPT-NEXT: GIR_Done,
|
||||||
// NOOPT-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
|
// NOOPT-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
|
||||||
|
|
||||||
@ -974,6 +976,31 @@ def MOVcimm8 : I<(outs GPR32:$dst), (ins i32imm:$imm), [(set GPR32:$dst, cimm8:$
|
|||||||
def LOAD : I<(outs GPR32:$dst), (ins GPR32:$src1),
|
def LOAD : I<(outs GPR32:$dst), (ins GPR32:$src1),
|
||||||
[(set GPR32:$dst, (load GPR32:$src1))]>;
|
[(set GPR32:$dst, (load GPR32:$src1))]>;
|
||||||
|
|
||||||
|
//===- Test a simple pattern with explicit pointer operands. ---------------===//
|
||||||
|
|
||||||
|
// NOOPT-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
|
||||||
|
// NOOPT-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
|
||||||
|
// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_LOAD,
|
||||||
|
// NOOPT-NEXT: GIM_CheckMemorySizeEqualToLLT, /*MI*/0, /*MMO*/0, /*OpIdx*/0,
|
||||||
|
// NOOPT-NEXT: GIM_CheckAtomicOrdering, /*MI*/0, /*Order*/(int64_t)AtomicOrdering::NotAtomic,
|
||||||
|
// NOOPT-NEXT: // MIs[0] dst
|
||||||
|
// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_p0s32,
|
||||||
|
// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
|
||||||
|
// NOOPT-NEXT: // MIs[0] src
|
||||||
|
// NOOPT-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/32,
|
||||||
|
// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
|
||||||
|
// NOOPT-NEXT: // (ld:{ *:[i32] } GPR32:{ *:[i32] }:$src)<<P:Predicate_unindexedload>><<P:Predicate_load>> => (LOAD:{ *:[i32] } GPR32:{ *:[i32] }:$src)
|
||||||
|
// NOOPT-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/MyTarget::LOAD,
|
||||||
|
// NOOPT-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
|
||||||
|
// NOOPT-NEXT: // GIR_Coverage, 23,
|
||||||
|
// NOOPT-NEXT: GIR_Done,
|
||||||
|
// NOOPT-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
|
||||||
|
|
||||||
|
def p0 : PtrValueType <i32, 0>;
|
||||||
|
|
||||||
|
def : Pat<(load GPR32:$src),
|
||||||
|
(p0 (LOAD GPR32:$src))>;
|
||||||
|
|
||||||
//===- Test a simple pattern with a sextload -------------------------------===//
|
//===- Test a simple pattern with a sextload -------------------------------===//
|
||||||
//
|
//
|
||||||
// NOOPT-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
|
// NOOPT-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
|
||||||
@ -1061,7 +1088,7 @@ def DOUBLE : I<(outs GPR32:$dst), (ins GPR32:$src), [(set GPR32:$dst, (add GPR32
|
|||||||
// NOOPT-NEXT: // (add:{ *:[i32] } i32:{ *:[i32] }:$src1, i32:{ *:[i32] }:$src2) => (ADD:{ *:[i32] } i32:{ *:[i32] }:$src1, i32:{ *:[i32] }:$src2)
|
// NOOPT-NEXT: // (add:{ *:[i32] } i32:{ *:[i32] }:$src1, i32:{ *:[i32] }:$src2) => (ADD:{ *:[i32] } i32:{ *:[i32] }:$src1, i32:{ *:[i32] }:$src2)
|
||||||
// NOOPT-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/MyTarget::ADD,
|
// NOOPT-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/MyTarget::ADD,
|
||||||
// NOOPT-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
|
// NOOPT-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
|
||||||
// NOOPT-NEXT: // GIR_Coverage, 23,
|
// NOOPT-NEXT: // GIR_Coverage, 24,
|
||||||
// NOOPT-NEXT: GIR_Done,
|
// NOOPT-NEXT: GIR_Done,
|
||||||
// NOOPT-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
|
// NOOPT-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
|
||||||
|
|
||||||
@ -1113,7 +1140,7 @@ def MUL : I<(outs GPR32:$dst), (ins GPR32:$src2, GPR32:$src1),
|
|||||||
// NOOPT-NEXT: // (bitconvert:{ *:[i32] } FPR32:{ *:[f32] }:$src1) => (COPY_TO_REGCLASS:{ *:[i32] } FPR32:{ *:[f32] }:$src1, GPR32:{ *:[i32] })
|
// NOOPT-NEXT: // (bitconvert:{ *:[i32] } FPR32:{ *:[f32] }:$src1) => (COPY_TO_REGCLASS:{ *:[i32] } FPR32:{ *:[f32] }:$src1, GPR32:{ *:[i32] })
|
||||||
// NOOPT-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/TargetOpcode::COPY,
|
// NOOPT-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/TargetOpcode::COPY,
|
||||||
// NOOPT-NEXT: GIR_ConstrainOperandRC, /*InsnID*/0, /*Op*/0, /*RC GPR32*/1,
|
// NOOPT-NEXT: GIR_ConstrainOperandRC, /*InsnID*/0, /*Op*/0, /*RC GPR32*/1,
|
||||||
// NOOPT-NEXT: // GIR_Coverage, 24,
|
// NOOPT-NEXT: // GIR_Coverage, 25,
|
||||||
// NOOPT-NEXT: GIR_Done,
|
// NOOPT-NEXT: GIR_Done,
|
||||||
// NOOPT-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
|
// NOOPT-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
|
||||||
|
|
||||||
|
@ -67,8 +67,10 @@ static bool berase_if(MachineValueTypeSet &S, Predicate P) {
|
|||||||
// inference will apply to each mode separately.
|
// inference will apply to each mode separately.
|
||||||
|
|
||||||
TypeSetByHwMode::TypeSetByHwMode(ArrayRef<ValueTypeByHwMode> VTList) {
|
TypeSetByHwMode::TypeSetByHwMode(ArrayRef<ValueTypeByHwMode> VTList) {
|
||||||
for (const ValueTypeByHwMode &VVT : VTList)
|
for (const ValueTypeByHwMode &VVT : VTList) {
|
||||||
insert(VVT);
|
insert(VVT);
|
||||||
|
AddrSpaces.push_back(VVT.PtrAddrSpace);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TypeSetByHwMode::isValueTypeByHwMode(bool AllowEmpty) const {
|
bool TypeSetByHwMode::isValueTypeByHwMode(bool AllowEmpty) const {
|
||||||
@ -85,9 +87,13 @@ ValueTypeByHwMode TypeSetByHwMode::getValueTypeByHwMode() const {
|
|||||||
assert(isValueTypeByHwMode(true) &&
|
assert(isValueTypeByHwMode(true) &&
|
||||||
"The type set has multiple types for at least one HW mode");
|
"The type set has multiple types for at least one HW mode");
|
||||||
ValueTypeByHwMode VVT;
|
ValueTypeByHwMode VVT;
|
||||||
|
auto ASI = AddrSpaces.begin();
|
||||||
|
|
||||||
for (const auto &I : *this) {
|
for (const auto &I : *this) {
|
||||||
MVT T = I.second.empty() ? MVT::Other : *I.second.begin();
|
MVT T = I.second.empty() ? MVT::Other : *I.second.begin();
|
||||||
VVT.getOrCreateTypeForMode(I.first, T);
|
VVT.getOrCreateTypeForMode(I.first, T);
|
||||||
|
if (ASI != AddrSpaces.end())
|
||||||
|
VVT.PtrAddrSpace = *ASI++;
|
||||||
}
|
}
|
||||||
return VVT;
|
return VVT;
|
||||||
}
|
}
|
||||||
|
@ -190,6 +190,7 @@ private:
|
|||||||
|
|
||||||
struct TypeSetByHwMode : public InfoByHwMode<MachineValueTypeSet> {
|
struct TypeSetByHwMode : public InfoByHwMode<MachineValueTypeSet> {
|
||||||
using SetType = MachineValueTypeSet;
|
using SetType = MachineValueTypeSet;
|
||||||
|
std::vector<unsigned> AddrSpaces;
|
||||||
|
|
||||||
TypeSetByHwMode() = default;
|
TypeSetByHwMode() = default;
|
||||||
TypeSetByHwMode(const TypeSetByHwMode &VTS) = default;
|
TypeSetByHwMode(const TypeSetByHwMode &VTS) = default;
|
||||||
@ -226,6 +227,15 @@ struct TypeSetByHwMode : public InfoByHwMode<MachineValueTypeSet> {
|
|||||||
return Map.size() == 1 && Map.begin()->first == DefaultMode;
|
return Map.size() == 1 && Map.begin()->first == DefaultMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isPointer() const {
|
||||||
|
return getValueTypeByHwMode().isPointer();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned getPtrAddrSpace() const {
|
||||||
|
assert(isPointer());
|
||||||
|
return getValueTypeByHwMode().PtrAddrSpace;
|
||||||
|
}
|
||||||
|
|
||||||
bool insert(const ValueTypeByHwMode &VVT);
|
bool insert(const ValueTypeByHwMode &VVT);
|
||||||
bool constrain(const TypeSetByHwMode &VTS);
|
bool constrain(const TypeSetByHwMode &VTS);
|
||||||
template <typename Predicate> bool constrain(Predicate P);
|
template <typename Predicate> bool constrain(Predicate P);
|
||||||
@ -242,6 +252,7 @@ struct TypeSetByHwMode : public InfoByHwMode<MachineValueTypeSet> {
|
|||||||
bool validate() const;
|
bool validate() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
unsigned PtrAddrSpace = std::numeric_limits<unsigned>::max();
|
||||||
/// Intersect two sets. Return true if anything has changed.
|
/// Intersect two sets. Return true if anything has changed.
|
||||||
bool intersect(SetType &Out, const SetType &In);
|
bool intersect(SetType &Out, const SetType &In);
|
||||||
};
|
};
|
||||||
|
@ -1513,6 +1513,9 @@ Error OperandMatcher::addTypeCheckPredicate(const TypeSetByHwMode &VTy,
|
|||||||
|
|
||||||
if (OperandIsAPointer)
|
if (OperandIsAPointer)
|
||||||
addPredicate<PointerToAnyOperandMatcher>(OpTyOrNone->get().getSizeInBits());
|
addPredicate<PointerToAnyOperandMatcher>(OpTyOrNone->get().getSizeInBits());
|
||||||
|
else if (VTy.isPointer())
|
||||||
|
addPredicate<LLTOperandMatcher>(LLT::pointer(VTy.getPtrAddrSpace(),
|
||||||
|
OpTyOrNone->get().getSizeInBits()));
|
||||||
else
|
else
|
||||||
addPredicate<LLTOperandMatcher>(*OpTyOrNone);
|
addPredicate<LLTOperandMatcher>(*OpTyOrNone);
|
||||||
return Error::success();
|
return Error::success();
|
||||||
|
@ -38,6 +38,11 @@ ValueTypeByHwMode::ValueTypeByHwMode(Record *R, const CodeGenHwModes &CGH) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ValueTypeByHwMode::ValueTypeByHwMode(Record *R, MVT T) : ValueTypeByHwMode(T) {
|
||||||
|
if (R->isSubClassOf("PtrValueType"))
|
||||||
|
PtrAddrSpace = R->getValueAsInt("AddrSpace");
|
||||||
|
}
|
||||||
|
|
||||||
bool ValueTypeByHwMode::operator== (const ValueTypeByHwMode &T) const {
|
bool ValueTypeByHwMode::operator== (const ValueTypeByHwMode &T) const {
|
||||||
assert(isValid() && T.isValid() && "Invalid type in assignment");
|
assert(isValid() && T.isValid() && "Invalid type in assignment");
|
||||||
bool Simple = isSimple();
|
bool Simple = isSimple();
|
||||||
@ -111,7 +116,7 @@ ValueTypeByHwMode llvm::getValueTypeByHwMode(Record *Rec,
|
|||||||
"Record must be derived from ValueType");
|
"Record must be derived from ValueType");
|
||||||
if (Rec->isSubClassOf("HwModeSelect"))
|
if (Rec->isSubClassOf("HwModeSelect"))
|
||||||
return ValueTypeByHwMode(Rec, CGH);
|
return ValueTypeByHwMode(Rec, CGH);
|
||||||
return ValueTypeByHwMode(llvm::getValueType(Rec));
|
return ValueTypeByHwMode(Rec, llvm::getValueType(Rec));
|
||||||
}
|
}
|
||||||
|
|
||||||
RegSizeInfo::RegSizeInfo(Record *R, const CodeGenHwModes &CGH) {
|
RegSizeInfo::RegSizeInfo(Record *R, const CodeGenHwModes &CGH) {
|
||||||
|
@ -119,6 +119,7 @@ struct InfoByHwMode {
|
|||||||
|
|
||||||
struct ValueTypeByHwMode : public InfoByHwMode<MVT> {
|
struct ValueTypeByHwMode : public InfoByHwMode<MVT> {
|
||||||
ValueTypeByHwMode(Record *R, const CodeGenHwModes &CGH);
|
ValueTypeByHwMode(Record *R, const CodeGenHwModes &CGH);
|
||||||
|
ValueTypeByHwMode(Record *R, MVT T);
|
||||||
ValueTypeByHwMode(MVT T) { Map.insert({DefaultMode,T}); }
|
ValueTypeByHwMode(MVT T) { Map.insert({DefaultMode,T}); }
|
||||||
ValueTypeByHwMode() = default;
|
ValueTypeByHwMode() = default;
|
||||||
|
|
||||||
@ -134,6 +135,11 @@ struct ValueTypeByHwMode : public InfoByHwMode<MVT> {
|
|||||||
static StringRef getMVTName(MVT T);
|
static StringRef getMVTName(MVT T);
|
||||||
void writeToStream(raw_ostream &OS) const;
|
void writeToStream(raw_ostream &OS) const;
|
||||||
void dump() const;
|
void dump() const;
|
||||||
|
|
||||||
|
unsigned PtrAddrSpace = std::numeric_limits<unsigned>::max();
|
||||||
|
bool isPointer() const {
|
||||||
|
return PtrAddrSpace != std::numeric_limits<unsigned>::max();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ValueTypeByHwMode getValueTypeByHwMode(Record *Rec,
|
ValueTypeByHwMode getValueTypeByHwMode(Record *Rec,
|
||||||
|
Loading…
Reference in New Issue
Block a user