Intrinsics: introduce llvm_any_ty aka ValueType Any

Specifically, gc.result benefits from this greatly. Instead of:

gc.result.int.*
gc.result.float.*
gc.result.ptr.*
...

We now have a gc.result.* that can specialize to literally any type.

Differential Revision: http://reviews.llvm.org/D7020

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@226857 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Ramkumar Ramachandra 2015-01-22 20:14:38 +00:00
parent 7ed0364cee
commit 230796b278
15 changed files with 58 additions and 53 deletions

View File

@ -236,13 +236,7 @@ Syntax:
::
declare type*
@gc.result_ptr(i32 %statepoint_token)
declare fX
@gc.result_float(i32 %statepoint_token)
declare iX
@gc.result_int(i32 %statepoint_token)
@gc.result(i32 %statepoint_token)
Overview:
"""""""""

View File

@ -152,7 +152,11 @@ namespace llvm {
// iPTR - An int value the size of the pointer of the current
// target. This should only be used internal to tblgen!
iPTR = 255
iPTR = 255,
// Any - Any type. This is used for intrinsics that have overloadings.
// This is only for tblgen's consumption!
Any = 256
};
SimpleValueType SimpleTy;
@ -245,7 +249,8 @@ namespace llvm {
/// isOverloaded - Return true if this is an overloaded type for TableGen.
bool isOverloaded() const {
return (SimpleTy==MVT::iAny || SimpleTy==MVT::fAny ||
return (SimpleTy==MVT::Any ||
SimpleTy==MVT::iAny || SimpleTy==MVT::fAny ||
SimpleTy==MVT::vAny || SimpleTy==MVT::iPTRAny);
}
@ -380,6 +385,7 @@ namespace llvm {
case iAny:
case fAny:
case vAny:
case Any:
llvm_unreachable("Value type is overloaded.");
case Metadata:
llvm_unreachable("Value type is metadata.");

View File

@ -98,3 +98,6 @@ def iAny : ValueType<0 , 254>;
// Pseudo valuetype mapped to the current pointer size.
def iPTR : ValueType<0 , 255>;
// Pseudo valuetype to represent "any type of any size".
def Any : ValueType<0 , 256>;

View File

@ -41,7 +41,7 @@ namespace Intrinsic {
#undef GET_INTRINSIC_ENUM_VALUES
, num_intrinsics
};
/// Return the LLVM name for an intrinsic, such as "llvm.ppc.altivec.lvx".
std::string getName(ID id, ArrayRef<Type*> Tys = None);
@ -69,7 +69,7 @@ namespace Intrinsic {
/// Map a MS builtin name to an intrinsic ID.
ID getIntrinsicForMSBuiltin(const char *Prefix, const char *BuiltinName);
/// This is a type descriptor which explains the type requirements of an
/// intrinsic. This is returned by getIntrinsicInfoTableEntries.
struct IITDescriptor {
@ -79,7 +79,7 @@ namespace Intrinsic {
Argument, ExtendArgument, TruncArgument, HalfVecArgument,
SameVecWidthArgument, PtrToArgument
} Kind;
union {
unsigned Integer_Width;
unsigned Float_Width;
@ -88,8 +88,9 @@ namespace Intrinsic {
unsigned Struct_NumElements;
unsigned Argument_Info;
};
enum ArgKind {
AK_Any,
AK_AnyInteger,
AK_AnyFloat,
AK_AnyVector,
@ -99,25 +100,25 @@ namespace Intrinsic {
assert(Kind == Argument || Kind == ExtendArgument ||
Kind == TruncArgument || Kind == HalfVecArgument ||
Kind == SameVecWidthArgument || Kind == PtrToArgument);
return Argument_Info >> 2;
return Argument_Info >> 3;
}
ArgKind getArgumentKind() const {
assert(Kind == Argument || Kind == ExtendArgument ||
Kind == TruncArgument || Kind == HalfVecArgument ||
Kind == SameVecWidthArgument || Kind == PtrToArgument);
return (ArgKind)(Argument_Info & 3);
return (ArgKind)(Argument_Info & 7);
}
static IITDescriptor get(IITDescriptorKind K, unsigned Field) {
IITDescriptor Result = { K, { Field } };
return Result;
}
};
/// Return the IIT table descriptor for the specified intrinsic into an array
/// of IITDescriptors.
void getIntrinsicInfoTableEntries(ID id, SmallVectorImpl<IITDescriptor> &T);
} // End Intrinsic namespace
} // End llvm namespace

View File

@ -123,6 +123,7 @@ class LLVMPointerTo<int num> : LLVMMatchType<num>;
class LLVMHalfElementsVectorType<int num> : LLVMMatchType<num>;
def llvm_void_ty : LLVMType<isVoid>;
def llvm_any_ty : LLVMType<Any>;
def llvm_anyint_ty : LLVMType<iAny>;
def llvm_anyfloat_ty : LLVMType<fAny>;
def llvm_anyvector_ty : LLVMType<vAny>;
@ -516,14 +517,16 @@ def int_experimental_gc_statepoint : Intrinsic<[llvm_i32_ty],
[llvm_anyptr_ty, llvm_i32_ty,
llvm_i32_ty, llvm_vararg_ty]>;
def int_experimental_gc_result_int : Intrinsic<[llvm_anyint_ty], [llvm_i32_ty]>;
def int_experimental_gc_result_float : Intrinsic<[llvm_anyfloat_ty],
[llvm_i32_ty]>;
def int_experimental_gc_result_ptr : Intrinsic<[llvm_anyptr_ty], [llvm_i32_ty]>;
def int_experimental_gc_result : Intrinsic<[llvm_any_ty], [llvm_i32_ty]>;
def int_experimental_gc_relocate : Intrinsic<[llvm_anyptr_ty],
[llvm_i32_ty, llvm_i32_ty, llvm_i32_ty]>;
// Deprecated: will be removed in a couple of weeks
def int_experimental_gc_result_int : Intrinsic<[llvm_anyint_ty], [llvm_i32_ty]>;
def int_experimental_gc_result_float : Intrinsic<[llvm_anyfloat_ty],
[llvm_i32_ty]>;
def int_experimental_gc_result_ptr : Intrinsic<[llvm_anyptr_ty], [llvm_i32_ty]>;
//===-------------------------- Other Intrinsics --------------------------===//
//
def int_flt_rounds : Intrinsic<[llvm_i32_ty]>,

View File

@ -416,6 +416,7 @@ struct NoTTI final : ImmutablePass, TargetTransformInfo {
case Intrinsic::experimental_gc_result_int:
case Intrinsic::experimental_gc_result_float:
case Intrinsic::experimental_gc_result_ptr:
case Intrinsic::experimental_gc_result:
case Intrinsic::experimental_gc_relocate:
// These intrinsics don't actually represent code after lowering.
return TCC_Free;

View File

@ -5604,7 +5604,8 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) {
}
case Intrinsic::experimental_gc_result_int:
case Intrinsic::experimental_gc_result_float:
case Intrinsic::experimental_gc_result_ptr: {
case Intrinsic::experimental_gc_result_ptr:
case Intrinsic::experimental_gc_result: {
visitGCResult(I);
return nullptr;
}

View File

@ -263,16 +263,7 @@ CallInst *IRBuilderBase::CreateGCStatepoint(Value *ActualCallee,
CallInst *IRBuilderBase::CreateGCResult(Instruction *Statepoint,
Type *ResultType,
const Twine &Name) {
Intrinsic::ID ID;
if (ResultType->isIntegerTy()) {
ID = Intrinsic::experimental_gc_result_int;
} else if (ResultType->isFloatingPointTy()) {
ID = Intrinsic::experimental_gc_result_float;
} else if (ResultType->isPointerTy()) {
ID = Intrinsic::experimental_gc_result_ptr;
} else {
llvm_unreachable("unimplemented result type for gc.result");
}
Intrinsic::ID ID = Intrinsic::experimental_gc_result;
Module *M = BB->getParent()->getParent();
Type *Types[] = {ResultType};
Value *FnGCResult = Intrinsic::getDeclaration(M, ID, Types);

View File

@ -54,7 +54,8 @@ bool llvm::isGCResult(const Instruction *inst) {
if (Function *F = call->getCalledFunction()) {
return (F->getIntrinsicID() == Intrinsic::experimental_gc_result_int ||
F->getIntrinsicID() == Intrinsic::experimental_gc_result_float ||
F->getIntrinsicID() == Intrinsic::experimental_gc_result_ptr);
F->getIntrinsicID() == Intrinsic::experimental_gc_result_ptr ||
F->getIntrinsicID() == Intrinsic::experimental_gc_result);
}
}
return false;

View File

@ -2391,6 +2391,7 @@ bool Verifier::VerifyIntrinsicType(Type *Ty,
ArgTys.push_back(Ty);
switch (D.getArgumentKind()) {
case IITDescriptor::AK_Any: return false; // Success
case IITDescriptor::AK_AnyInteger: return !Ty->isIntOrIntVectorTy();
case IITDescriptor::AK_AnyFloat: return !Ty->isFPOrFPVectorTy();
case IITDescriptor::AK_AnyVector: return !isa<VectorType>(Ty);
@ -2721,7 +2722,8 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) {
}
case Intrinsic::experimental_gc_result_int:
case Intrinsic::experimental_gc_result_float:
case Intrinsic::experimental_gc_result_ptr: {
case Intrinsic::experimental_gc_result_ptr:
case Intrinsic::experimental_gc_result: {
// Are we tied to a statepoint properly?
CallSite StatepointCS(CI.getArgOperand(0));
const Function *StatepointFn =

View File

@ -21,7 +21,7 @@ define i1 @test_i1_return() gc "statepoint-example" {
; CHECK: retq
entry:
%safepoint_token = tail call i32 (i1 ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_i1f(i1 ()* @return_i1, i32 0, i32 0, i32 0)
%call1 = call zeroext i1 @llvm.experimental.gc.result.int.i1(i32 %safepoint_token)
%call1 = call zeroext i1 @llvm.experimental.gc.result.i1(i32 %safepoint_token)
ret i1 %call1
}
@ -33,7 +33,7 @@ define i32 @test_i32_return() gc "statepoint-example" {
; CHECK: retq
entry:
%safepoint_token = tail call i32 (i32 ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_i32f(i32 ()* @return_i32, i32 0, i32 0, i32 0)
%call1 = call zeroext i32 @llvm.experimental.gc.result.int.i32(i32 %safepoint_token)
%call1 = call zeroext i32 @llvm.experimental.gc.result.i32(i32 %safepoint_token)
ret i32 %call1
}
@ -45,7 +45,7 @@ define i32* @test_i32ptr_return() gc "statepoint-example" {
; CHECK: retq
entry:
%safepoint_token = tail call i32 (i32* ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_p0i32f(i32* ()* @return_i32ptr, i32 0, i32 0, i32 0)
%call1 = call i32* @llvm.experimental.gc.result.ptr.p0i32(i32 %safepoint_token)
%call1 = call i32* @llvm.experimental.gc.result.p0i32(i32 %safepoint_token)
ret i32* %call1
}
@ -57,7 +57,7 @@ define float @test_float_return() gc "statepoint-example" {
; CHECK: retq
entry:
%safepoint_token = tail call i32 (float ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_f32f(float ()* @return_float, i32 0, i32 0, i32 0)
%call1 = call float @llvm.experimental.gc.result.float.f32(i32 %safepoint_token)
%call1 = call float @llvm.experimental.gc.result.f32(i32 %safepoint_token)
ret float %call1
}
@ -72,7 +72,7 @@ define i1 @test_relocate(i32 addrspace(1)* %a) gc "statepoint-example" {
entry:
%safepoint_token = tail call i32 (i1 ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_i1f(i1 ()* @return_i1, i32 0, i32 0, i32 0, i32 addrspace(1)* %a)
%call1 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(i32 %safepoint_token, i32 4, i32 4)
%call2 = call zeroext i1 @llvm.experimental.gc.result.int.i1(i32 %safepoint_token)
%call2 = call zeroext i1 @llvm.experimental.gc.result.i1(i32 %safepoint_token)
ret i1 %call2
}
@ -88,16 +88,16 @@ entry:
}
declare i32 @llvm.experimental.gc.statepoint.p0f_i1f(i1 ()*, i32, i32, ...)
declare i1 @llvm.experimental.gc.result.int.i1(i32)
declare i1 @llvm.experimental.gc.result.i1(i32)
declare i32 @llvm.experimental.gc.statepoint.p0f_i32f(i32 ()*, i32, i32, ...)
declare i32 @llvm.experimental.gc.result.int.i32(i32)
declare i32 @llvm.experimental.gc.result.i32(i32)
declare i32 @llvm.experimental.gc.statepoint.p0f_p0i32f(i32* ()*, i32, i32, ...)
declare i32* @llvm.experimental.gc.result.ptr.p0i32(i32)
declare i32* @llvm.experimental.gc.result.p0i32(i32)
declare i32 @llvm.experimental.gc.statepoint.p0f_f32f(float ()*, i32, i32, ...)
declare float @llvm.experimental.gc.result.float.f32(i32)
declare float @llvm.experimental.gc.result.f32(i32)
declare i32 @llvm.experimental.gc.statepoint.p0f_isVoidi32varargf(void (i32, ...)*, i32, i32, ...)

View File

@ -22,7 +22,7 @@ entry:
%metadata1 = alloca i32 addrspace(1)*, i32 2, align 8
store i32 addrspace(1)* null, i32 addrspace(1)** %metadata1
%safepoint_token = tail call i32 (i1 ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_i1f(i1 ()* @return_i1, i32 0, i32 0, i32 2, i32 addrspace(1)* %ptr, i32 addrspace(1)* null, i32 addrspace(1)* %ptr, i32 addrspace(1)* null)
%call1 = call zeroext i1 @llvm.experimental.gc.result.int.i1(i32 %safepoint_token)
%call1 = call zeroext i1 @llvm.experimental.gc.result.i1(i32 %safepoint_token)
%a = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(i32 %safepoint_token, i32 6, i32 6)
%b = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(i32 %safepoint_token, i32 7, i32 7)
;
@ -30,7 +30,7 @@ entry:
}
declare i32 @llvm.experimental.gc.statepoint.p0f_i1f(i1 ()*, i32, i32, ...)
declare i1 @llvm.experimental.gc.result.int.i1(i32)
declare i1 @llvm.experimental.gc.result.i1(i32)
declare i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(i32, i32, i32) #3

View File

@ -53,7 +53,7 @@ EEVT::TypeSet::TypeSet(MVT::SimpleValueType VT, TreePattern &TP) {
EnforceVector(TP);
else {
assert((VT < MVT::LAST_VALUETYPE || VT == MVT::iPTR ||
VT == MVT::iPTRAny) && "Not a concrete type!");
VT == MVT::iPTRAny || VT == MVT::Any) && "Not a concrete type!");
TypeVec.push_back(VT);
}
}

View File

@ -57,6 +57,7 @@ std::string llvm::getEnumName(MVT::SimpleValueType T) {
case MVT::i32: return "MVT::i32";
case MVT::i64: return "MVT::i64";
case MVT::i128: return "MVT::i128";
case MVT::Any: return "MVT::Any";
case MVT::iAny: return "MVT::iAny";
case MVT::fAny: return "MVT::fAny";
case MVT::vAny: return "MVT::vAny";

View File

@ -309,7 +309,7 @@ static void EncodeFixedType(Record *R, std::vector<unsigned char> &ArgCodes,
Sig.push_back(IIT_HALF_VEC_ARG);
else if (R->isSubClassOf("LLVMVectorSameWidth")) {
Sig.push_back(IIT_SAME_VEC_WIDTH_ARG);
Sig.push_back((Number << 2) | ArgCodes[Number]);
Sig.push_back((Number << 3) | ArgCodes[Number]);
MVT::SimpleValueType VT = getValueType(R->getValueAsDef("ElTy"));
EncodeFixedValueType(VT, Sig);
return;
@ -319,7 +319,7 @@ static void EncodeFixedType(Record *R, std::vector<unsigned char> &ArgCodes,
}
else
Sig.push_back(IIT_ARG);
return Sig.push_back((Number << 2) | ArgCodes[Number]);
return Sig.push_back((Number << 3) | ArgCodes[Number]);
}
MVT::SimpleValueType VT = getValueType(R->getValueAsDef("VT"));
@ -330,7 +330,8 @@ static void EncodeFixedType(Record *R, std::vector<unsigned char> &ArgCodes,
case MVT::iPTRAny: ++Tmp; // FALL THROUGH.
case MVT::vAny: ++Tmp; // FALL THROUGH.
case MVT::fAny: ++Tmp; // FALL THROUGH.
case MVT::iAny: {
case MVT::iAny: ++Tmp; // FALL THROUGH.
case MVT::Any: {
// If this is an "any" valuetype, then the type is the type of the next
// type in the list specified to getIntrinsic().
Sig.push_back(IIT_ARG);
@ -339,8 +340,8 @@ static void EncodeFixedType(Record *R, std::vector<unsigned char> &ArgCodes,
unsigned ArgNo = ArgCodes.size();
ArgCodes.push_back(Tmp);
// Encode what sort of argument it must be in the low 2 bits of the ArgNo.
return Sig.push_back((ArgNo << 2) | Tmp);
// Encode what sort of argument it must be in the low 3 bits of the ArgNo.
return Sig.push_back((ArgNo << 3) | Tmp);
}
case MVT::iPTR: {