forked from OSchip/llvm-project
[Clang][RISCV] Implement vlseg and vlsegff.
Differential Revision: https://reviews.llvm.org/D103527
This commit is contained in:
parent
b16400449f
commit
593bf9b4de
|
@ -56,7 +56,7 @@ using IdentifierLocPair = std::pair<IdentifierInfo *, SourceLocation>;
|
|||
/// of a pointer to one of these classes.
|
||||
enum { IdentifierInfoAlignment = 8 };
|
||||
|
||||
static constexpr int ObjCOrBuiltinIDBits = 15;
|
||||
static constexpr int ObjCOrBuiltinIDBits = 16;
|
||||
|
||||
/// One of these records is kept for each identifier that
|
||||
/// is lexed. This contains information about whether the token was \#define'd,
|
||||
|
|
|
@ -203,6 +203,8 @@ class RVVBuiltin<string suffix, string prototype, string type_range,
|
|||
// Sub extension of vector spec. Currently only support Zvamo or Zvlsseg.
|
||||
string RequiredExtension = "";
|
||||
|
||||
// Number of fields for Zvlsseg.
|
||||
int NF = 1;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -768,6 +770,163 @@ multiclass RVVIndexedStore<string op> {
|
|||
}
|
||||
}
|
||||
|
||||
defvar NFList = [2, 3, 4, 5, 6, 7, 8];
|
||||
|
||||
class PVString<int nf, bit signed> {
|
||||
string S =
|
||||
!cond(!eq(nf, 2): !if(signed, "PvPv", "PUvPUv"),
|
||||
!eq(nf, 3): !if(signed, "PvPvPv", "PUvPUvPUv"),
|
||||
!eq(nf, 4): !if(signed, "PvPvPvPv", "PUvPUvPUvPUv"),
|
||||
!eq(nf, 5): !if(signed, "PvPvPvPvPv", "PUvPUvPUvPUvPUv"),
|
||||
!eq(nf, 6): !if(signed, "PvPvPvPvPvPv", "PUvPUvPUvPUvPUvPUv"),
|
||||
!eq(nf, 7): !if(signed, "PvPvPvPvPvPvPv", "PUvPUvPUvPUvPUvPUvPUv"),
|
||||
!eq(nf, 8): !if(signed, "PvPvPvPvPvPvPvPv", "PUvPUvPUvPUvPUvPUvPUvPUv"));
|
||||
}
|
||||
|
||||
multiclass RVVUnitStridedSegLoad<string op> {
|
||||
foreach type = TypeList in {
|
||||
defvar eew = !cond(!eq(type, "c") : "8",
|
||||
!eq(type, "s") : "16",
|
||||
!eq(type, "i") : "32",
|
||||
!eq(type, "l") : "64",
|
||||
!eq(type, "h") : "16",
|
||||
!eq(type, "f") : "32",
|
||||
!eq(type, "d") : "64");
|
||||
foreach nf = NFList in {
|
||||
let Name = op # nf # "e" # eew # "_v",
|
||||
IRName = op # nf,
|
||||
IRNameMask = op # nf # "_mask",
|
||||
NF = nf,
|
||||
HasNoMaskedOverloaded = false,
|
||||
ManualCodegen = [{
|
||||
{
|
||||
// builtin: (val0 address, val1 address, ..., ptr, vl)
|
||||
IntrinsicTypes = {Ops[0]->getType()->getPointerElementType(),
|
||||
Ops[NF + 1]->getType()};
|
||||
// intrinsic: (ptr, vl)
|
||||
llvm::Value *Operands[] = {Ops[NF], Ops[NF + 1]};
|
||||
llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
|
||||
llvm::Value *LoadValue = Builder.CreateCall(F, Operands, "");
|
||||
clang::CharUnits Align =
|
||||
CGM.getNaturalTypeAlignment(getContext().getSizeType());
|
||||
llvm::Value *V;
|
||||
for (unsigned I = 0; I < NF; ++I) {
|
||||
V = Builder.CreateStore(Builder.CreateExtractValue(LoadValue, {I}),
|
||||
Address(Ops[I], Align));
|
||||
}
|
||||
return V;
|
||||
}
|
||||
}],
|
||||
ManualCodegenMask = [{
|
||||
{
|
||||
// builtin: (val0 address, ..., mask, maskedoff0, ..., ptr, vl)
|
||||
// intrinsic: (maskedoff0, ..., ptr, mask, vl)
|
||||
IntrinsicTypes = {Ops[0]->getType()->getPointerElementType(),
|
||||
Ops[2 * NF + 2]->getType()};
|
||||
SmallVector<llvm::Value*, 12> Operands;
|
||||
for (unsigned I = 0; I < NF; ++I)
|
||||
Operands.push_back(Ops[NF + I + 1]);
|
||||
Operands.push_back(Ops[2 * NF + 1]);
|
||||
Operands.push_back(Ops[NF]);
|
||||
Operands.push_back(Ops[2 * NF + 2]);
|
||||
assert(Operands.size() == NF + 3);
|
||||
llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
|
||||
llvm::Value *LoadValue = Builder.CreateCall(F, Operands, "");
|
||||
clang::CharUnits Align =
|
||||
CGM.getNaturalTypeAlignment(getContext().getSizeType());
|
||||
llvm::Value *V;
|
||||
for (unsigned I = 0; I < NF; ++I) {
|
||||
V = Builder.CreateStore(Builder.CreateExtractValue(LoadValue, {I}),
|
||||
Address(Ops[I], Align));
|
||||
}
|
||||
return V;
|
||||
}
|
||||
}] in {
|
||||
defvar PV = PVString<nf, /*signed=*/true>.S;
|
||||
defvar PUV = PVString<nf, /*signed=*/false>.S;
|
||||
def : RVVBuiltin<"v", "0" # PV # "PCe", type>;
|
||||
if !not(IsFloat<type>.val) then {
|
||||
def : RVVBuiltin<"Uv", "0" # PUV # "PCUe", type>;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
multiclass RVVUnitStridedSegLoadFF<string op> {
|
||||
foreach type = TypeList in {
|
||||
defvar eew = !cond(!eq(type, "c") : "8",
|
||||
!eq(type, "s") : "16",
|
||||
!eq(type, "i") : "32",
|
||||
!eq(type, "l") : "64",
|
||||
!eq(type, "h") : "16",
|
||||
!eq(type, "f") : "32",
|
||||
!eq(type, "d") : "64");
|
||||
foreach nf = NFList in {
|
||||
let Name = op # nf # "e" # eew # "ff_v",
|
||||
IRName = op # nf # "ff",
|
||||
IRNameMask = op # nf # "ff_mask",
|
||||
NF = nf,
|
||||
HasNoMaskedOverloaded = false,
|
||||
ManualCodegen = [{
|
||||
{
|
||||
// builtin: (val0 address, val1 address, ..., ptr, new_vl, vl)
|
||||
IntrinsicTypes = {Ops[0]->getType()->getPointerElementType(),
|
||||
Ops[NF + 2]->getType()};
|
||||
// intrinsic: (ptr, vl)
|
||||
llvm::Value *Operands[] = {Ops[NF], Ops[NF + 2]};
|
||||
Value *NewVL = Ops[NF + 1];
|
||||
llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
|
||||
llvm::Value *LoadValue = Builder.CreateCall(F, Operands, "");
|
||||
clang::CharUnits Align =
|
||||
CGM.getNaturalTypeAlignment(getContext().getSizeType());
|
||||
for (unsigned I = 0; I < NF; ++I) {
|
||||
Builder.CreateStore(Builder.CreateExtractValue(LoadValue, {I}),
|
||||
Address(Ops[I], Align));
|
||||
}
|
||||
// Store new_vl.
|
||||
return Builder.CreateStore(Builder.CreateExtractValue(LoadValue, {NF}),
|
||||
Address(NewVL, Align));
|
||||
}
|
||||
}],
|
||||
ManualCodegenMask = [{
|
||||
{
|
||||
// builtin: (val0 address, ..., mask, maskedoff0, ..., ptr, new_vl, vl)
|
||||
// intrinsic: (maskedoff0, ..., ptr, mask, vl)
|
||||
IntrinsicTypes = {Ops[0]->getType()->getPointerElementType(),
|
||||
Ops[2 * NF + 3]->getType()};
|
||||
SmallVector<llvm::Value*, 12> Operands;
|
||||
for (unsigned I = 0; I < NF; ++I)
|
||||
Operands.push_back(Ops[NF + I + 1]);
|
||||
Operands.push_back(Ops[2 * NF + 1]);
|
||||
Operands.push_back(Ops[NF]);
|
||||
Operands.push_back(Ops[2 * NF + 3]);
|
||||
Value *NewVL = Ops[2 * NF + 2];
|
||||
assert(Operands.size() == NF + 3);
|
||||
llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
|
||||
llvm::Value *LoadValue = Builder.CreateCall(F, Operands, "");
|
||||
clang::CharUnits Align =
|
||||
CGM.getNaturalTypeAlignment(getContext().getSizeType());
|
||||
for (unsigned I = 0; I < NF; ++I) {
|
||||
Builder.CreateStore(Builder.CreateExtractValue(LoadValue, {I}),
|
||||
Address(Ops[I], Align));
|
||||
}
|
||||
// Store new_vl.
|
||||
return Builder.CreateStore(Builder.CreateExtractValue(LoadValue, {NF}),
|
||||
Address(NewVL, Align));
|
||||
}
|
||||
}] in {
|
||||
defvar PV = PVString<nf, /*signed=*/true>.S;
|
||||
defvar PUV = PVString<nf, /*signed=*/false>.S;
|
||||
def : RVVBuiltin<"v", "0" # PV # "PCe" # "Pz", type>;
|
||||
if !not(IsFloat<type>.val) then {
|
||||
def : RVVBuiltin<"Uv", "0" # PUV # "PCUe" # "Pz", type>;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
multiclass RVVAMOBuiltinSet<bit has_signed = false, bit has_unsigned = false,
|
||||
bit has_fp = false> {
|
||||
defvar type_list = !if(has_fp, ["i","l","f","d"], ["i","l"]);
|
||||
|
@ -1083,6 +1242,12 @@ defm vle16ff: RVVVLEFFBuiltin<["s"]>;
|
|||
defm vle32ff: RVVVLEFFBuiltin<["i", "f"]>;
|
||||
defm vle64ff: RVVVLEFFBuiltin<["l", "d"]>;
|
||||
|
||||
// 7.8 Vector Load/Store Segment Instructions
|
||||
let RequiredExtension = "Zvlsseg" in {
|
||||
defm : RVVUnitStridedSegLoad<"vlseg">;
|
||||
defm : RVVUnitStridedSegLoadFF<"vlseg">;
|
||||
}
|
||||
|
||||
// 8. Vector AMO Operations
|
||||
let RequiredExtension = "Zvamo" in {
|
||||
defm vamoswap : RVVAMOBuiltinSet< /* hasSigned */ true, /* hasUnsigned */ true, /* hasFP */ true>;
|
||||
|
|
|
@ -18062,6 +18062,7 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID,
|
|||
Ops.push_back(EmitScalarExpr(E->getArg(i)));
|
||||
|
||||
Intrinsic::ID ID = Intrinsic::not_intrinsic;
|
||||
unsigned NF = 1;
|
||||
|
||||
// Required for overloaded intrinsics.
|
||||
llvm::SmallVector<llvm::Type *, 2> IntrinsicTypes;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -165,6 +165,7 @@ private:
|
|||
// InputTypes. -1 means the return type.
|
||||
std::vector<int64_t> IntrinsicTypes;
|
||||
uint8_t RISCVExtensions = 0;
|
||||
unsigned NF = 1;
|
||||
|
||||
public:
|
||||
RVVIntrinsic(StringRef Name, StringRef Suffix, StringRef MangledName,
|
||||
|
@ -172,7 +173,7 @@ public:
|
|||
bool HasMaskedOffOperand, bool HasVL, bool HasNoMaskedOverloaded,
|
||||
bool HasAutoDef, StringRef ManualCodegen, const RVVTypes &Types,
|
||||
const std::vector<int64_t> &IntrinsicTypes,
|
||||
StringRef RequiredExtension);
|
||||
StringRef RequiredExtension, unsigned NF);
|
||||
~RVVIntrinsic() = default;
|
||||
|
||||
StringRef getName() const { return Name; }
|
||||
|
@ -187,6 +188,7 @@ public:
|
|||
StringRef getIRName() const { return IRName; }
|
||||
StringRef getManualCodegen() const { return ManualCodegen; }
|
||||
uint8_t getRISCVExtensions() const { return RISCVExtensions; }
|
||||
unsigned getNF() const { return NF; }
|
||||
|
||||
// Return the type string for a BUILTIN() macro in Builtins.def.
|
||||
std::string getBuiltinTypeStr() const;
|
||||
|
@ -231,7 +233,7 @@ private:
|
|||
/// and LMUL with type transformers). It also record result of type in legal
|
||||
/// or illegal set to avoid compute the same config again. The result maybe
|
||||
/// have illegal RVVType.
|
||||
Optional<RVVTypes> computeTypes(BasicType BT, int Log2LMUL,
|
||||
Optional<RVVTypes> computeTypes(BasicType BT, int Log2LMUL, unsigned NF,
|
||||
ArrayRef<std::string> PrototypeSeq);
|
||||
Optional<RVVTypePtr> computeType(BasicType BT, int Log2LMUL, StringRef Proto);
|
||||
|
||||
|
@ -436,6 +438,11 @@ void RVVType::initBuiltinStr() {
|
|||
return;
|
||||
}
|
||||
BuiltinStr = "q" + utostr(Scale.getValue()) + BuiltinStr;
|
||||
// Pointer to vector types. Defined for Zvlsseg load intrinsics.
|
||||
// Zvlsseg load intrinsics have pointer type arguments to store the loaded
|
||||
// vector values.
|
||||
if (IsPointer)
|
||||
BuiltinStr += "*";
|
||||
}
|
||||
|
||||
void RVVType::initClangBuiltinStr() {
|
||||
|
@ -749,11 +756,11 @@ RVVIntrinsic::RVVIntrinsic(StringRef NewName, StringRef Suffix,
|
|||
bool HasNoMaskedOverloaded, bool HasAutoDef,
|
||||
StringRef ManualCodegen, const RVVTypes &OutInTypes,
|
||||
const std::vector<int64_t> &NewIntrinsicTypes,
|
||||
StringRef RequiredExtension)
|
||||
StringRef RequiredExtension, unsigned NF)
|
||||
: IRName(IRName), HasSideEffects(HasSideEffects), IsMask(IsMask),
|
||||
HasMaskedOffOperand(HasMaskedOffOperand), HasVL(HasVL),
|
||||
HasNoMaskedOverloaded(HasNoMaskedOverloaded), HasAutoDef(HasAutoDef),
|
||||
ManualCodegen(ManualCodegen.str()) {
|
||||
ManualCodegen(ManualCodegen.str()), NF(NF) {
|
||||
|
||||
// Init Name and MangledName
|
||||
Name = NewName.str();
|
||||
|
@ -788,7 +795,7 @@ RVVIntrinsic::RVVIntrinsic(StringRef NewName, StringRef Suffix,
|
|||
if (IsMask && HasMaskedOffOperand) {
|
||||
for (auto &I : IntrinsicTypes) {
|
||||
if (I >= 0)
|
||||
I += 1;
|
||||
I += NF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -805,6 +812,8 @@ std::string RVVIntrinsic::getBuiltinTypeStr() const {
|
|||
void RVVIntrinsic::emitCodeGenSwitchBody(raw_ostream &OS) const {
|
||||
if (!getIRName().empty())
|
||||
OS << " ID = Intrinsic::riscv_" + getIRName() + ";\n";
|
||||
if (NF >= 2)
|
||||
OS << " NF = " + utostr(getNF()) + ";\n";
|
||||
if (hasManualCodegen()) {
|
||||
OS << ManualCodegen;
|
||||
OS << "break;\n";
|
||||
|
@ -1076,6 +1085,7 @@ void RVVEmitter::createRVVIntrinsics(
|
|||
StringRef RequiredExtension = R->getValueAsString("RequiredExtension");
|
||||
StringRef IRName = R->getValueAsString("IRName");
|
||||
StringRef IRNameMask = R->getValueAsString("IRNameMask");
|
||||
unsigned NF = R->getValueAsInt("NF");
|
||||
|
||||
StringRef HeaderCodeStr = R->getValueAsString("HeaderCode");
|
||||
bool HasAutoDef = HeaderCodeStr.empty();
|
||||
|
@ -1093,10 +1103,31 @@ void RVVEmitter::createRVVIntrinsics(
|
|||
SmallVector<std::string> ProtoMaskSeq = ProtoSeq;
|
||||
if (HasMask) {
|
||||
// If HasMaskedOffOperand, insert result type as first input operand.
|
||||
if (HasMaskedOffOperand)
|
||||
ProtoMaskSeq.insert(ProtoMaskSeq.begin() + 1, ProtoSeq[0]);
|
||||
// If HasMask, insert 'm' as first input operand.
|
||||
ProtoMaskSeq.insert(ProtoMaskSeq.begin() + 1, "m");
|
||||
if (HasMaskedOffOperand) {
|
||||
if (NF == 1) {
|
||||
ProtoMaskSeq.insert(ProtoMaskSeq.begin() + 1, ProtoSeq[0]);
|
||||
} else {
|
||||
// Convert
|
||||
// (void, op0 address, op1 address, ...)
|
||||
// to
|
||||
// (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...)
|
||||
for (unsigned I = 0; I < NF; ++I)
|
||||
ProtoMaskSeq.insert(
|
||||
ProtoMaskSeq.begin() + NF + 1,
|
||||
ProtoSeq[1].substr(1)); // Use substr(1) to skip '*'
|
||||
}
|
||||
}
|
||||
if (HasMaskedOffOperand && NF > 1) {
|
||||
// Convert
|
||||
// (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...)
|
||||
// to
|
||||
// (void, op0 address, op1 address, ..., mask, maskedoff0, maskedoff1,
|
||||
// ...)
|
||||
ProtoMaskSeq.insert(ProtoMaskSeq.begin() + NF + 1, "m");
|
||||
} else {
|
||||
// If HasMask, insert 'm' as first input operand.
|
||||
ProtoMaskSeq.insert(ProtoMaskSeq.begin() + 1, "m");
|
||||
}
|
||||
}
|
||||
// If HasVL, append 'z' to last operand
|
||||
if (HasVL) {
|
||||
|
@ -1107,7 +1138,7 @@ void RVVEmitter::createRVVIntrinsics(
|
|||
// Create Intrinsics for each type and LMUL.
|
||||
for (char I : TypeRange) {
|
||||
for (int Log2LMUL : Log2LMULList) {
|
||||
Optional<RVVTypes> Types = computeTypes(I, Log2LMUL, ProtoSeq);
|
||||
Optional<RVVTypes> Types = computeTypes(I, Log2LMUL, NF, ProtoSeq);
|
||||
// Ignored to create new intrinsic if there are any illegal types.
|
||||
if (!Types.hasValue())
|
||||
continue;
|
||||
|
@ -1118,16 +1149,16 @@ void RVVEmitter::createRVVIntrinsics(
|
|||
Name, SuffixStr, MangledName, IRName, HasSideEffects,
|
||||
/*IsMask=*/false, /*HasMaskedOffOperand=*/false, HasVL,
|
||||
HasNoMaskedOverloaded, HasAutoDef, ManualCodegen, Types.getValue(),
|
||||
IntrinsicTypes, RequiredExtension));
|
||||
IntrinsicTypes, RequiredExtension, NF));
|
||||
if (HasMask) {
|
||||
// Create a mask intrinsic
|
||||
Optional<RVVTypes> MaskTypes =
|
||||
computeTypes(I, Log2LMUL, ProtoMaskSeq);
|
||||
computeTypes(I, Log2LMUL, NF, ProtoMaskSeq);
|
||||
Out.push_back(std::make_unique<RVVIntrinsic>(
|
||||
Name, SuffixStr, MangledName, IRNameMask, HasSideEffects,
|
||||
/*IsMask=*/true, HasMaskedOffOperand, HasVL,
|
||||
HasNoMaskedOverloaded, HasAutoDef, ManualCodegenMask,
|
||||
MaskTypes.getValue(), IntrinsicTypes, RequiredExtension));
|
||||
MaskTypes.getValue(), IntrinsicTypes, RequiredExtension, NF));
|
||||
}
|
||||
} // end for Log2LMULList
|
||||
} // end for TypeRange
|
||||
|
@ -1135,8 +1166,12 @@ void RVVEmitter::createRVVIntrinsics(
|
|||
}
|
||||
|
||||
Optional<RVVTypes>
|
||||
RVVEmitter::computeTypes(BasicType BT, int Log2LMUL,
|
||||
RVVEmitter::computeTypes(BasicType BT, int Log2LMUL, unsigned NF,
|
||||
ArrayRef<std::string> PrototypeSeq) {
|
||||
// LMUL x NF must be less than or equal to 8.
|
||||
if ((Log2LMUL >= 1) && (1 << Log2LMUL) * NF > 8)
|
||||
return llvm::None;
|
||||
|
||||
RVVTypes Types;
|
||||
for (const std::string &Proto : PrototypeSeq) {
|
||||
auto T = computeType(BT, Log2LMUL, Proto);
|
||||
|
|
Loading…
Reference in New Issue