Changeset View
Standalone View
llvm/include/llvm/Analysis/TargetTransformInfo.h
Show First 20 Lines • Show All 788 Lines • ▼ Show 20 Lines | enum OperandValueKind { | ||||
OK_UniformValue, // Operand is uniform (splat of a value). | OK_UniformValue, // Operand is uniform (splat of a value). | ||||
OK_UniformConstantValue, // Operand is uniform constant. | OK_UniformConstantValue, // Operand is uniform constant. | ||||
OK_NonUniformConstantValue // Operand is a non uniform constant value. | OK_NonUniformConstantValue // Operand is a non uniform constant value. | ||||
}; | }; | ||||
/// Additional properties of an operand's values. | /// Additional properties of an operand's values. | ||||
enum OperandValueProperties { OP_None = 0, OP_PowerOf2 = 1 }; | enum OperandValueProperties { OP_None = 0, OP_PowerOf2 = 1 }; | ||||
/// \return The number of scalar or vector registers that the target has. | /// \return the number of registers in the target-provided register class. | ||||
/// If 'Vectors' is true, it returns the number of vector registers. If it is | unsigned getNumberOfRegisters(unsigned ClassID) const; | ||||
hfinkel: I'm not sure that these defaults make sense. Many targets won't even have these as distinct… | |||||
/// set to false, it returns the number of scalar registers. | |||||
unsigned getNumberOfRegisters(bool Vector) const; | /// return the target-provided register class for the provided type. | ||||
unsigned getRegisterClassForType(Type *Ty, bool Vector) const; | |||||
Not Done ReplyInline ActionsI don't like spreading the concept of register classes corresponding to types. I also don't think register classes as a concept should be leaking out to the IR arsenm: I don't like spreading the concept of register classes corresponding to types.
I also don't… | |||||
I think it's not the concept of register class in backend. It's an abstraction of register class in backend and just to classify and distinguish different kinds of data residing in different register position to help estimate register pressure. wuzish: I think it's not the concept of register class in backend. It's an abstraction of register… | |||||
Yeah, I think that it's pretty important that these are *abstract* register classes - used to establish the mapping between the types of IR values and the number of simultaneous live ranges to which we'd like to limit for some set of those types - it's probably worth stating that explicitly in the description. hfinkel: Yeah, I think that it's pretty important that these are *abstract* register classes - used to… | |||||
Not Done ReplyInline ActionsCan we explicitly call out the fact that these are not the CodeGen register classes? Also, how about making the interface a getRegisterClassForValue as opposed to getRegisterClassForType? This would allow a context-sensitive determination of register classes. Specifically, in the AMDGPU backend, it would potentially allow us to distinguish between uniform and divergent values (in the overall program sense). nhaehnle: Can we explicitly call out the fact that these are not the CodeGen register classes?
Also, how… | |||||
Not Done ReplyInline Actions
I think that's a good idea. We can say that this is designed to provide a simple, high-level view of the register allocation later process later performed by the backend. These register classes don't necessarily map onto the register classes used by the backend.
I don't object, but we should make sure to think about the overall computational complexity of the analysis the backend would need to use, and whether this per-value interface will allow that analysis to be performed efficiently. hfinkel: > Can we explicitly call out the fact that these are not the CodeGen register classes?
I think… | |||||
if use getRegisterClassForValue, I find a scene to distinguish 2 different register class in PowerPC target. For the i1 type generated from icmp, there are 8 CRRC, but there are 32 CRBITRC for the i1 type generated from other operation. Is this required? @hfinkel wuzish: if use `getRegisterClassForValue`, I find a scene to distinguish 2 different register class in… | |||||
/// return the target-provided register class name | |||||
const char* getRegisterClassName(unsigned ClassID) const; | |||||
/// \return The width of the largest scalar or vector register type. | /// \return The width of the largest scalar or vector register type. | ||||
unsigned getRegisterBitWidth(bool Vector) const; | unsigned getRegisterBitWidth(bool Vector) const; | ||||
/// \return The width of the smallest vector register type. | /// \return The width of the smallest vector register type. | ||||
unsigned getMinVectorRegisterBitWidth() const; | unsigned getMinVectorRegisterBitWidth() const; | ||||
/// \return True if the vectorization factor should be chosen to | /// \return True if the vectorization factor should be chosen to | ||||
▲ Show 20 Lines • Show All 437 Lines • ▼ Show 20 Lines | public: | ||||
virtual int getFPOpCost(Type *Ty) = 0; | virtual int getFPOpCost(Type *Ty) = 0; | ||||
virtual int getIntImmCodeSizeCost(unsigned Opc, unsigned Idx, const APInt &Imm, | virtual int getIntImmCodeSizeCost(unsigned Opc, unsigned Idx, const APInt &Imm, | ||||
Type *Ty) = 0; | Type *Ty) = 0; | ||||
virtual int getIntImmCost(const APInt &Imm, Type *Ty) = 0; | virtual int getIntImmCost(const APInt &Imm, Type *Ty) = 0; | ||||
virtual int getIntImmCost(unsigned Opc, unsigned Idx, const APInt &Imm, | virtual int getIntImmCost(unsigned Opc, unsigned Idx, const APInt &Imm, | ||||
Type *Ty) = 0; | Type *Ty) = 0; | ||||
virtual int getIntImmCost(Intrinsic::ID IID, unsigned Idx, const APInt &Imm, | virtual int getIntImmCost(Intrinsic::ID IID, unsigned Idx, const APInt &Imm, | ||||
Type *Ty) = 0; | Type *Ty) = 0; | ||||
virtual unsigned getNumberOfRegisters(bool Vector) = 0; | virtual unsigned getNumberOfRegisters(unsigned ClassID) const = 0; | ||||
virtual unsigned getRegisterClassForType(Type *Ty, bool Vector) const = 0; | |||||
virtual const char* getRegisterClassName(unsigned ClassID) const = 0; | |||||
virtual unsigned getRegisterBitWidth(bool Vector) const = 0; | virtual unsigned getRegisterBitWidth(bool Vector) const = 0; | ||||
virtual unsigned getMinVectorRegisterBitWidth() = 0; | virtual unsigned getMinVectorRegisterBitWidth() = 0; | ||||
virtual bool shouldMaximizeVectorBandwidth(bool OptSize) const = 0; | virtual bool shouldMaximizeVectorBandwidth(bool OptSize) const = 0; | ||||
virtual unsigned getMinimumVF(unsigned ElemWidth) const = 0; | virtual unsigned getMinimumVF(unsigned ElemWidth) const = 0; | ||||
virtual bool shouldConsiderAddressTypePromotion( | virtual bool shouldConsiderAddressTypePromotion( | ||||
const Instruction &I, bool &AllowPromotionWithoutCommonHeader) = 0; | const Instruction &I, bool &AllowPromotionWithoutCommonHeader) = 0; | ||||
virtual unsigned getCacheLineSize() = 0; | virtual unsigned getCacheLineSize() = 0; | ||||
virtual llvm::Optional<unsigned> getCacheSize(CacheLevel Level) = 0; | virtual llvm::Optional<unsigned> getCacheSize(CacheLevel Level) = 0; | ||||
▲ Show 20 Lines • Show All 328 Lines • ▼ Show 20 Lines | public: | ||||
int getIntImmCost(unsigned Opc, unsigned Idx, const APInt &Imm, | int getIntImmCost(unsigned Opc, unsigned Idx, const APInt &Imm, | ||||
Type *Ty) override { | Type *Ty) override { | ||||
return Impl.getIntImmCost(Opc, Idx, Imm, Ty); | return Impl.getIntImmCost(Opc, Idx, Imm, Ty); | ||||
} | } | ||||
int getIntImmCost(Intrinsic::ID IID, unsigned Idx, const APInt &Imm, | int getIntImmCost(Intrinsic::ID IID, unsigned Idx, const APInt &Imm, | ||||
Type *Ty) override { | Type *Ty) override { | ||||
return Impl.getIntImmCost(IID, Idx, Imm, Ty); | return Impl.getIntImmCost(IID, Idx, Imm, Ty); | ||||
} | } | ||||
unsigned getNumberOfRegisters(bool Vector) override { | unsigned getNumberOfRegisters(unsigned ClassID) const override { | ||||
return Impl.getNumberOfRegisters(Vector); | return Impl.getNumberOfRegisters(ClassID); | ||||
} | |||||
unsigned getRegisterClassForType(Type *Ty, bool Vector) const override { | |||||
return Impl.getRegisterClassForType(Ty, Vector); | |||||
} | |||||
const char* getRegisterClassName(unsigned ClassID) const override { | |||||
return Impl.getRegisterClassName(ClassID); | |||||
} | } | ||||
unsigned getRegisterBitWidth(bool Vector) const override { | unsigned getRegisterBitWidth(bool Vector) const override { | ||||
return Impl.getRegisterBitWidth(Vector); | return Impl.getRegisterBitWidth(Vector); | ||||
} | } | ||||
unsigned getMinVectorRegisterBitWidth() override { | unsigned getMinVectorRegisterBitWidth() override { | ||||
return Impl.getMinVectorRegisterBitWidth(); | return Impl.getMinVectorRegisterBitWidth(); | ||||
} | } | ||||
bool shouldMaximizeVectorBandwidth(bool OptSize) const override { | bool shouldMaximizeVectorBandwidth(bool OptSize) const override { | ||||
▲ Show 20 Lines • Show All 304 Lines • Show Last 20 Lines |
I'm not sure that these defaults make sense. Many targets won't even have these as distinct classes (e.g., PowerPC with VSX). I think that we should have the default implementation just return one register class, 0, with its current default (which I suppose is 8 registers), and the default implementation will put everything in that one class. Then, I don't think that we need this enum at all.
My impression is that you decided to do it this way so that you could write in the other targets:
but I think it's better to just give all of the other targets which did something with Vector two register classes, and return the second one for all types which are vector types. That should match the current behavior and then the targets can customize as they see fit. But I'd leave this all within each target (there's no need to expose generic classes because there's no need for a generic meaning).