Intrinsics: expand semantics of LLVMExtendedVectorType (& trunc)

These are used in the ARM backends to aid type-checking on patterns involving
intrinsics. By making sure one argument is an extended/truncated version of
another.

However, there's no reason to limit them to just vectors types. For example
AArch64 has the instruction "uqshrn sD, dN, #imm" which would naturally use an
intrinsic taking an i64 and returning an i32.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@205003 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Tim Northover 2014-03-28 12:31:39 +00:00
parent efb8deb640
commit b7de4288bc
8 changed files with 74 additions and 55 deletions

View File

@ -79,7 +79,7 @@ namespace Intrinsic {
enum IITDescriptorKind {
Void, VarArg, MMX, Metadata, Half, Float, Double,
Integer, Vector, Pointer, Struct,
Argument, ExtendVecArgument, TruncVecArgument
Argument, ExtendArgument, TruncArgument,
} Kind;
union {
@ -98,13 +98,13 @@ namespace Intrinsic {
AK_AnyPointer
};
unsigned getArgumentNumber() const {
assert(Kind == Argument || Kind == ExtendVecArgument ||
Kind == TruncVecArgument);
assert(Kind == Argument || Kind == ExtendArgument ||
Kind == TruncArgument);
return Argument_Info >> 2;
}
ArgKind getArgumentKind() const {
assert(Kind == Argument || Kind == ExtendVecArgument ||
Kind == TruncVecArgument);
assert(Kind == Argument || Kind == ExtendArgument ||
Kind == TruncArgument);
return (ArgKind)(Argument_Info&3);
}

View File

@ -106,12 +106,12 @@ class LLVMMatchType<int num>
int Number = num;
}
// Match the type of another intrinsic parameter that is expected to be
// an integral vector type, but change the element size to be twice as wide
// or half as wide as the other type. This is only useful when the intrinsic
// is overloaded, so the matched type should be declared as iAny.
class LLVMExtendedElementVectorType<int num> : LLVMMatchType<num>;
class LLVMTruncatedElementVectorType<int num> : LLVMMatchType<num>;
// Match the type of another intrinsic parameter that is expected to be based on
// an integral type (i.e. either iN or <N x iM>), but change the scalar size to
// be twice as wide or half as wide as the other type. This is only useful when
// the intrinsic is overloaded, so the matched type should be declared as iAny.
class LLVMExtendedType<int num> : LLVMMatchType<num>;
class LLVMTruncatedType<int num> : LLVMMatchType<num>;
def llvm_void_ty : LLVMType<isVoid>;
def llvm_anyint_ty : LLVMType<iAny>;

View File

@ -68,7 +68,7 @@ class Neon_N3V_Intrinsic
[IntrNoMem]>;
class Neon_N2V_Narrow_Intrinsic
: Intrinsic<[llvm_anyvector_ty],
[LLVMExtendedElementVectorType<0>, llvm_i32_ty],
[LLVMExtendedType<0>, llvm_i32_ty],
[IntrNoMem]>;
// Vector rounding shift right by immediate (Signed)

View File

@ -131,20 +131,15 @@ def int_arm_sevl : Intrinsic<[], []>;
class Neon_1Arg_Intrinsic
: Intrinsic<[llvm_anyvector_ty], [LLVMMatchType<0>], [IntrNoMem]>;
class Neon_1Arg_Narrow_Intrinsic
: Intrinsic<[llvm_anyvector_ty],
[LLVMExtendedElementVectorType<0>], [IntrNoMem]>;
: Intrinsic<[llvm_anyvector_ty], [LLVMExtendedType<0>], [IntrNoMem]>;
class Neon_2Arg_Intrinsic
: Intrinsic<[llvm_anyvector_ty], [LLVMMatchType<0>, LLVMMatchType<0>],
[IntrNoMem]>;
class Neon_2Arg_Narrow_Intrinsic
: Intrinsic<[llvm_anyvector_ty],
[LLVMExtendedElementVectorType<0>,
LLVMExtendedElementVectorType<0>],
: Intrinsic<[llvm_anyvector_ty], [LLVMExtendedType<0>, LLVMExtendedType<0>],
[IntrNoMem]>;
class Neon_2Arg_Long_Intrinsic
: Intrinsic<[llvm_anyvector_ty],
[LLVMTruncatedElementVectorType<0>,
LLVMTruncatedElementVectorType<0>],
: Intrinsic<[llvm_anyvector_ty], [LLVMTruncatedType<0>, LLVMTruncatedType<0>],
[IntrNoMem]>;
class Neon_3Arg_Intrinsic
: Intrinsic<[llvm_anyvector_ty],
@ -152,9 +147,7 @@ class Neon_3Arg_Intrinsic
[IntrNoMem]>;
class Neon_3Arg_Long_Intrinsic
: Intrinsic<[llvm_anyvector_ty],
[LLVMMatchType<0>,
LLVMTruncatedElementVectorType<0>,
LLVMTruncatedElementVectorType<0>],
[LLVMMatchType<0>, LLVMTruncatedType<0>, LLVMTruncatedType<0>],
[IntrNoMem]>;
class Neon_CvtFxToFP_Intrinsic
: Intrinsic<[llvm_anyfloat_ty], [llvm_anyint_ty, llvm_i32_ty], [IntrNoMem]>;

View File

@ -466,8 +466,8 @@ enum IIT_Info {
IIT_STRUCT3 = 20,
IIT_STRUCT4 = 21,
IIT_STRUCT5 = 22,
IIT_EXTEND_VEC_ARG = 23,
IIT_TRUNC_VEC_ARG = 24,
IIT_EXTEND_ARG = 23,
IIT_TRUNC_ARG = 24,
IIT_ANYPTR = 25,
IIT_V1 = 26,
IIT_VARARG = 27
@ -556,15 +556,15 @@ static void DecodeIITType(unsigned &NextElt, ArrayRef<unsigned char> Infos,
OutputTable.push_back(IITDescriptor::get(IITDescriptor::Argument, ArgInfo));
return;
}
case IIT_EXTEND_VEC_ARG: {
case IIT_EXTEND_ARG: {
unsigned ArgInfo = (NextElt == Infos.size() ? 0 : Infos[NextElt++]);
OutputTable.push_back(IITDescriptor::get(IITDescriptor::ExtendVecArgument,
OutputTable.push_back(IITDescriptor::get(IITDescriptor::ExtendArgument,
ArgInfo));
return;
}
case IIT_TRUNC_VEC_ARG: {
case IIT_TRUNC_ARG: {
unsigned ArgInfo = (NextElt == Infos.size() ? 0 : Infos[NextElt++]);
OutputTable.push_back(IITDescriptor::get(IITDescriptor::TruncVecArgument,
OutputTable.push_back(IITDescriptor::get(IITDescriptor::TruncArgument,
ArgInfo));
return;
}
@ -656,13 +656,22 @@ static Type *DecodeFixedType(ArrayRef<Intrinsic::IITDescriptor> &Infos,
case IITDescriptor::Argument:
return Tys[D.getArgumentNumber()];
case IITDescriptor::ExtendVecArgument:
return VectorType::getExtendedElementVectorType(cast<VectorType>(
Tys[D.getArgumentNumber()]));
case IITDescriptor::ExtendArgument: {
Type *Ty = Tys[D.getArgumentNumber()];
if (VectorType *VTy = dyn_cast<VectorType>(Ty))
return VectorType::getExtendedElementVectorType(VTy);
case IITDescriptor::TruncVecArgument:
return VectorType::getTruncatedElementVectorType(cast<VectorType>(
Tys[D.getArgumentNumber()]));
return IntegerType::get(Context, 2 * cast<IntegerType>(Ty)->getBitWidth());
}
case IITDescriptor::TruncArgument: {
Type *Ty = Tys[D.getArgumentNumber()];
if (VectorType *VTy = dyn_cast<VectorType>(Ty))
return VectorType::getTruncatedElementVectorType(VTy);
IntegerType *ITy = cast<IntegerType>(Ty);
assert(ITy->getBitWidth() % 2 == 0);
return IntegerType::get(Context, ITy->getBitWidth() / 2);
}
}
llvm_unreachable("unhandled");
}

View File

@ -2176,19 +2176,36 @@ bool Verifier::VerifyIntrinsicType(Type *Ty,
}
llvm_unreachable("all argument kinds not covered");
case IITDescriptor::ExtendVecArgument:
case IITDescriptor::ExtendArgument: {
// This may only be used when referring to a previous vector argument.
return D.getArgumentNumber() >= ArgTys.size() ||
!isa<VectorType>(ArgTys[D.getArgumentNumber()]) ||
VectorType::getExtendedElementVectorType(
cast<VectorType>(ArgTys[D.getArgumentNumber()])) != Ty;
if (D.getArgumentNumber() >= ArgTys.size())
return true;
case IITDescriptor::TruncVecArgument:
Type *NewTy = ArgTys[D.getArgumentNumber()];
if (VectorType *VTy = dyn_cast<VectorType>(NewTy))
NewTy = VectorType::getExtendedElementVectorType(VTy);
else if (IntegerType *ITy = dyn_cast<IntegerType>(NewTy))
NewTy = IntegerType::get(ITy->getContext(), 2 * ITy->getBitWidth());
else
return true;
return Ty != NewTy;
}
case IITDescriptor::TruncArgument: {
// This may only be used when referring to a previous vector argument.
return D.getArgumentNumber() >= ArgTys.size() ||
!isa<VectorType>(ArgTys[D.getArgumentNumber()]) ||
VectorType::getTruncatedElementVectorType(
cast<VectorType>(ArgTys[D.getArgumentNumber()])) != Ty;
if (D.getArgumentNumber() >= ArgTys.size())
return true;
Type *NewTy = ArgTys[D.getArgumentNumber()];
if (VectorType *VTy = dyn_cast<VectorType>(NewTy))
NewTy = VectorType::getTruncatedElementVectorType(VTy);
else if (IntegerType *ITy = dyn_cast<IntegerType>(NewTy))
NewTy = IntegerType::get(ITy->getContext(), ITy->getBitWidth() / 2);
else
return true;
return Ty != NewTy;
}
}
llvm_unreachable("unhandled");
}

View File

@ -498,8 +498,8 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) {
// It only makes sense to use the extended and truncated vector element
// variants with iAny types; otherwise, if the intrinsic is not
// overloaded, all the types can be specified directly.
assert(((!TyEl->isSubClassOf("LLVMExtendedElementVectorType") &&
!TyEl->isSubClassOf("LLVMTruncatedElementVectorType")) ||
assert(((!TyEl->isSubClassOf("LLVMExtendedType") &&
!TyEl->isSubClassOf("LLVMTruncatedType")) ||
VT == MVT::iAny || VT == MVT::vAny) &&
"Expected iAny or vAny type");
} else {
@ -532,8 +532,8 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) {
// It only makes sense to use the extended and truncated vector element
// variants with iAny types; otherwise, if the intrinsic is not
// overloaded, all the types can be specified directly.
assert(((!TyEl->isSubClassOf("LLVMExtendedElementVectorType") &&
!TyEl->isSubClassOf("LLVMTruncatedElementVectorType")) ||
assert(((!TyEl->isSubClassOf("LLVMExtendedType") &&
!TyEl->isSubClassOf("LLVMTruncatedType")) ||
VT == MVT::iAny || VT == MVT::vAny) &&
"Expected iAny or vAny type");
} else

View File

@ -246,8 +246,8 @@ enum IIT_Info {
IIT_STRUCT3 = 20,
IIT_STRUCT4 = 21,
IIT_STRUCT5 = 22,
IIT_EXTEND_VEC_ARG = 23,
IIT_TRUNC_VEC_ARG = 24,
IIT_EXTEND_ARG = 23,
IIT_TRUNC_ARG = 24,
IIT_ANYPTR = 25,
IIT_V1 = 26,
IIT_VARARG = 27
@ -292,10 +292,10 @@ static void EncodeFixedType(Record *R, std::vector<unsigned char> &ArgCodes,
if (R->isSubClassOf("LLVMMatchType")) {
unsigned Number = R->getValueAsInt("Number");
assert(Number < ArgCodes.size() && "Invalid matching number!");
if (R->isSubClassOf("LLVMExtendedElementVectorType"))
Sig.push_back(IIT_EXTEND_VEC_ARG);
else if (R->isSubClassOf("LLVMTruncatedElementVectorType"))
Sig.push_back(IIT_TRUNC_VEC_ARG);
if (R->isSubClassOf("LLVMExtendedType"))
Sig.push_back(IIT_EXTEND_ARG);
else if (R->isSubClassOf("LLVMTruncatedType"))
Sig.push_back(IIT_TRUNC_ARG);
else
Sig.push_back(IIT_ARG);
return Sig.push_back((Number << 2) | ArgCodes[Number]);