mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-10-19 02:52:53 +02:00
Add speculatable function attribute
This attribute tells the optimizer that the function may be speculated. Patch by Tom Stellard llvm-svn: 301680
This commit is contained in:
parent
61aeea9876
commit
c9972a05d5
@ -1535,6 +1535,17 @@ example:
|
|||||||
``sanitize_thread``
|
``sanitize_thread``
|
||||||
This attribute indicates that ThreadSanitizer checks
|
This attribute indicates that ThreadSanitizer checks
|
||||||
(dynamic thread safety analysis) are enabled for this function.
|
(dynamic thread safety analysis) are enabled for this function.
|
||||||
|
``speculatable``
|
||||||
|
This function attribute indicates that the function does not have any
|
||||||
|
effects besides calculating its result and does not have undefined behavior.
|
||||||
|
Note that ``speculatable`` is not enough to conclude that along any
|
||||||
|
particular exection path the number of calls to this function will not be
|
||||||
|
externally observable. This attribute is only valid on functions
|
||||||
|
and declarations, not on individual call sites. If a function is
|
||||||
|
incorrectly marked as speculatable and really does exhibit
|
||||||
|
undefined behavior, the undefined behavior may be observed even
|
||||||
|
if the call site is dead code.
|
||||||
|
|
||||||
``ssp``
|
``ssp``
|
||||||
This attribute indicates that the function should emit a stack
|
This attribute indicates that the function should emit a stack
|
||||||
smashing protector. It is in the form of a "canary" --- a random value
|
smashing protector. It is in the form of a "canary" --- a random value
|
||||||
|
@ -545,7 +545,8 @@ enum AttributeKindCodes {
|
|||||||
ATTR_KIND_INACCESSIBLEMEM_ONLY = 49,
|
ATTR_KIND_INACCESSIBLEMEM_ONLY = 49,
|
||||||
ATTR_KIND_INACCESSIBLEMEM_OR_ARGMEMONLY = 50,
|
ATTR_KIND_INACCESSIBLEMEM_OR_ARGMEMONLY = 50,
|
||||||
ATTR_KIND_ALLOC_SIZE = 51,
|
ATTR_KIND_ALLOC_SIZE = 51,
|
||||||
ATTR_KIND_WRITEONLY = 52
|
ATTR_KIND_WRITEONLY = 52,
|
||||||
|
ATTR_KIND_SPECULATABLE = 53
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ComdatSelectionKindCodes {
|
enum ComdatSelectionKindCodes {
|
||||||
|
@ -137,6 +137,9 @@ def SExt : EnumAttr<"signext">;
|
|||||||
/// +1 bias 0 means unaligned (different from alignstack=(1)).
|
/// +1 bias 0 means unaligned (different from alignstack=(1)).
|
||||||
def StackAlignment : EnumAttr<"alignstack">;
|
def StackAlignment : EnumAttr<"alignstack">;
|
||||||
|
|
||||||
|
/// Function can be speculated.
|
||||||
|
def Speculatable : EnumAttr<"speculatable">;
|
||||||
|
|
||||||
/// Stack protection.
|
/// Stack protection.
|
||||||
def StackProtect : EnumAttr<"ssp">;
|
def StackProtect : EnumAttr<"ssp">;
|
||||||
|
|
||||||
|
@ -418,6 +418,14 @@ public:
|
|||||||
removeFnAttr(Attribute::Convergent);
|
removeFnAttr(Attribute::Convergent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Determine if the call has sideeffects.
|
||||||
|
bool isSpeculatable() const {
|
||||||
|
return hasFnAttribute(Attribute::Speculatable);
|
||||||
|
}
|
||||||
|
void setSpeculatable() {
|
||||||
|
addFnAttr(Attribute::Speculatable);
|
||||||
|
}
|
||||||
|
|
||||||
/// Determine if the function is known not to recurse, directly or
|
/// Determine if the function is known not to recurse, directly or
|
||||||
/// indirectly.
|
/// indirectly.
|
||||||
bool doesNotRecurse() const {
|
bool doesNotRecurse() const {
|
||||||
|
@ -98,6 +98,9 @@ def IntrNoDuplicate : IntrinsicProperty;
|
|||||||
// Parallels the convergent attribute on LLVM IR functions.
|
// Parallels the convergent attribute on LLVM IR functions.
|
||||||
def IntrConvergent : IntrinsicProperty;
|
def IntrConvergent : IntrinsicProperty;
|
||||||
|
|
||||||
|
// This property indicates that the intrinsic is safe to speculate.
|
||||||
|
def IntrSpeculatable : IntrinsicProperty;
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Types used by intrinsics.
|
// Types used by intrinsics.
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -648,6 +648,7 @@ lltok::Kind LLLexer::LexIdentifier() {
|
|||||||
KEYWORD(returned);
|
KEYWORD(returned);
|
||||||
KEYWORD(returns_twice);
|
KEYWORD(returns_twice);
|
||||||
KEYWORD(signext);
|
KEYWORD(signext);
|
||||||
|
KEYWORD(speculatable);
|
||||||
KEYWORD(sret);
|
KEYWORD(sret);
|
||||||
KEYWORD(ssp);
|
KEYWORD(ssp);
|
||||||
KEYWORD(sspreq);
|
KEYWORD(sspreq);
|
||||||
|
@ -1095,6 +1095,7 @@ bool LLParser::ParseFnAttributeValuePairs(AttrBuilder &B,
|
|||||||
case lltok::kw_readonly: B.addAttribute(Attribute::ReadOnly); break;
|
case lltok::kw_readonly: B.addAttribute(Attribute::ReadOnly); break;
|
||||||
case lltok::kw_returns_twice:
|
case lltok::kw_returns_twice:
|
||||||
B.addAttribute(Attribute::ReturnsTwice); break;
|
B.addAttribute(Attribute::ReturnsTwice); break;
|
||||||
|
case lltok::kw_speculatable: B.addAttribute(Attribute::Speculatable); break;
|
||||||
case lltok::kw_ssp: B.addAttribute(Attribute::StackProtect); break;
|
case lltok::kw_ssp: B.addAttribute(Attribute::StackProtect); break;
|
||||||
case lltok::kw_sspreq: B.addAttribute(Attribute::StackProtectReq); break;
|
case lltok::kw_sspreq: B.addAttribute(Attribute::StackProtectReq); break;
|
||||||
case lltok::kw_sspstrong:
|
case lltok::kw_sspstrong:
|
||||||
|
@ -198,6 +198,7 @@ enum Kind {
|
|||||||
kw_returned,
|
kw_returned,
|
||||||
kw_returns_twice,
|
kw_returns_twice,
|
||||||
kw_signext,
|
kw_signext,
|
||||||
|
kw_speculatable,
|
||||||
kw_ssp,
|
kw_ssp,
|
||||||
kw_sspreq,
|
kw_sspreq,
|
||||||
kw_sspstrong,
|
kw_sspstrong,
|
||||||
|
@ -1119,6 +1119,7 @@ static uint64_t getRawAttributeMask(Attribute::AttrKind Val) {
|
|||||||
case Attribute::SwiftSelf: return 1ULL << 51;
|
case Attribute::SwiftSelf: return 1ULL << 51;
|
||||||
case Attribute::SwiftError: return 1ULL << 52;
|
case Attribute::SwiftError: return 1ULL << 52;
|
||||||
case Attribute::WriteOnly: return 1ULL << 53;
|
case Attribute::WriteOnly: return 1ULL << 53;
|
||||||
|
case Attribute::Speculatable: return 1ULL << 54;
|
||||||
case Attribute::Dereferenceable:
|
case Attribute::Dereferenceable:
|
||||||
llvm_unreachable("dereferenceable attribute not supported in raw format");
|
llvm_unreachable("dereferenceable attribute not supported in raw format");
|
||||||
break;
|
break;
|
||||||
@ -1315,6 +1316,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
|
|||||||
return Attribute::ReturnsTwice;
|
return Attribute::ReturnsTwice;
|
||||||
case bitc::ATTR_KIND_S_EXT:
|
case bitc::ATTR_KIND_S_EXT:
|
||||||
return Attribute::SExt;
|
return Attribute::SExt;
|
||||||
|
case bitc::ATTR_KIND_SPECULATABLE:
|
||||||
|
return Attribute::Speculatable;
|
||||||
case bitc::ATTR_KIND_STACK_ALIGNMENT:
|
case bitc::ATTR_KIND_STACK_ALIGNMENT:
|
||||||
return Attribute::StackAlignment;
|
return Attribute::StackAlignment;
|
||||||
case bitc::ATTR_KIND_STACK_PROTECT:
|
case bitc::ATTR_KIND_STACK_PROTECT:
|
||||||
|
@ -688,6 +688,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
|
|||||||
return bitc::ATTR_KIND_RETURNS_TWICE;
|
return bitc::ATTR_KIND_RETURNS_TWICE;
|
||||||
case Attribute::SExt:
|
case Attribute::SExt:
|
||||||
return bitc::ATTR_KIND_S_EXT;
|
return bitc::ATTR_KIND_S_EXT;
|
||||||
|
case Attribute::Speculatable:
|
||||||
|
return bitc::ATTR_KIND_SPECULATABLE;
|
||||||
case Attribute::StackAlignment:
|
case Attribute::StackAlignment:
|
||||||
return bitc::ATTR_KIND_STACK_ALIGNMENT;
|
return bitc::ATTR_KIND_STACK_ALIGNMENT;
|
||||||
case Attribute::StackProtect:
|
case Attribute::StackProtect:
|
||||||
|
@ -315,6 +315,8 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
|
|||||||
return "returns_twice";
|
return "returns_twice";
|
||||||
if (hasAttribute(Attribute::SExt))
|
if (hasAttribute(Attribute::SExt))
|
||||||
return "signext";
|
return "signext";
|
||||||
|
if (hasAttribute(Attribute::Speculatable))
|
||||||
|
return "speculatable";
|
||||||
if (hasAttribute(Attribute::StackProtect))
|
if (hasAttribute(Attribute::StackProtect))
|
||||||
return "ssp";
|
return "ssp";
|
||||||
if (hasAttribute(Attribute::StackProtectReq))
|
if (hasAttribute(Attribute::StackProtectReq))
|
||||||
|
@ -1203,9 +1203,9 @@ void Verifier::visitComdat(const Comdat &C) {
|
|||||||
|
|
||||||
void Verifier::visitModuleIdents(const Module &M) {
|
void Verifier::visitModuleIdents(const Module &M) {
|
||||||
const NamedMDNode *Idents = M.getNamedMetadata("llvm.ident");
|
const NamedMDNode *Idents = M.getNamedMetadata("llvm.ident");
|
||||||
if (!Idents)
|
if (!Idents)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// llvm.ident takes a list of metadata entry. Each entry has only one string.
|
// llvm.ident takes a list of metadata entry. Each entry has only one string.
|
||||||
// Scan each llvm.ident entry and make sure that this requirement is met.
|
// Scan each llvm.ident entry and make sure that this requirement is met.
|
||||||
for (const MDNode *N : Idents->operands()) {
|
for (const MDNode *N : Idents->operands()) {
|
||||||
@ -1215,7 +1215,7 @@ void Verifier::visitModuleIdents(const Module &M) {
|
|||||||
("invalid value for llvm.ident metadata entry operand"
|
("invalid value for llvm.ident metadata entry operand"
|
||||||
"(the operand should be a string)"),
|
"(the operand should be a string)"),
|
||||||
N->getOperand(0));
|
N->getOperand(0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Verifier::visitModuleFlags(const Module &M) {
|
void Verifier::visitModuleFlags(const Module &M) {
|
||||||
@ -1352,6 +1352,7 @@ static bool isFuncOnlyAttr(Attribute::AttrKind Kind) {
|
|||||||
case Attribute::InaccessibleMemOnly:
|
case Attribute::InaccessibleMemOnly:
|
||||||
case Attribute::InaccessibleMemOrArgMemOnly:
|
case Attribute::InaccessibleMemOrArgMemOnly:
|
||||||
case Attribute::AllocSize:
|
case Attribute::AllocSize:
|
||||||
|
case Attribute::Speculatable:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -1837,7 +1838,7 @@ void Verifier::verifyStatepoint(ImmutableCallSite CS) {
|
|||||||
Assert(ExpectedNumArgs <= (int)CS.arg_size(),
|
Assert(ExpectedNumArgs <= (int)CS.arg_size(),
|
||||||
"gc.statepoint too few arguments according to length fields", &CI);
|
"gc.statepoint too few arguments according to length fields", &CI);
|
||||||
|
|
||||||
// Check that the only uses of this gc.statepoint are gc.result or
|
// Check that the only uses of this gc.statepoint are gc.result or
|
||||||
// gc.relocate calls which are tied to this statepoint and thus part
|
// gc.relocate calls which are tied to this statepoint and thus part
|
||||||
// of the same statepoint sequence
|
// of the same statepoint sequence
|
||||||
for (const User *U : CI.users()) {
|
for (const User *U : CI.users()) {
|
||||||
@ -2610,6 +2611,15 @@ void Verifier::verifyCallSite(CallSite CS) {
|
|||||||
Assert(verifyAttributeCount(Attrs, CS.arg_size()),
|
Assert(verifyAttributeCount(Attrs, CS.arg_size()),
|
||||||
"Attribute after last parameter!", I);
|
"Attribute after last parameter!", I);
|
||||||
|
|
||||||
|
if (Attrs.hasAttribute(AttributeList::FunctionIndex, Attribute::Speculatable)) {
|
||||||
|
// Don't allow speculatable on call sites, unless the underlying function
|
||||||
|
// declaration is also speculatable.
|
||||||
|
Function *Callee
|
||||||
|
= dyn_cast<Function>(CS.getCalledValue()->stripPointerCasts());
|
||||||
|
Assert(Callee && Callee->isSpeculatable(),
|
||||||
|
"speculatable attribute may not apply to call sites", I);
|
||||||
|
}
|
||||||
|
|
||||||
// Verify call attributes.
|
// Verify call attributes.
|
||||||
verifyFunctionAttrs(FTy, Attrs, I);
|
verifyFunctionAttrs(FTy, Attrs, I);
|
||||||
|
|
||||||
@ -3908,7 +3918,7 @@ void Verifier::visitIntrinsicCallSite(Intrinsic::ID ID, CallSite CS) {
|
|||||||
|
|
||||||
// If the intrinsic takes MDNode arguments, verify that they are either global
|
// If the intrinsic takes MDNode arguments, verify that they are either global
|
||||||
// or are local to *this* function.
|
// or are local to *this* function.
|
||||||
for (Value *V : CS.args())
|
for (Value *V : CS.args())
|
||||||
if (auto *MD = dyn_cast<MetadataAsValue>(V))
|
if (auto *MD = dyn_cast<MetadataAsValue>(V))
|
||||||
visitMetadataAsValue(*MD, CS.getCaller());
|
visitMetadataAsValue(*MD, CS.getCaller());
|
||||||
|
|
||||||
@ -3981,7 +3991,7 @@ void Verifier::visitIntrinsicCallSite(Intrinsic::ID ID, CallSite CS) {
|
|||||||
auto IsValidAlignment = [&](uint64_t Alignment) {
|
auto IsValidAlignment = [&](uint64_t Alignment) {
|
||||||
return isPowerOf2_64(Alignment) && ElementSizeVal.ule(Alignment);
|
return isPowerOf2_64(Alignment) && ElementSizeVal.ule(Alignment);
|
||||||
};
|
};
|
||||||
|
|
||||||
uint64_t DstAlignment = CS.getParamAlignment(1),
|
uint64_t DstAlignment = CS.getParamAlignment(1),
|
||||||
SrcAlignment = CS.getParamAlignment(2);
|
SrcAlignment = CS.getParamAlignment(2);
|
||||||
|
|
||||||
@ -4220,7 +4230,7 @@ void Verifier::visitIntrinsicCallSite(Intrinsic::ID ID, CallSite CS) {
|
|||||||
}
|
}
|
||||||
case Intrinsic::masked_load: {
|
case Intrinsic::masked_load: {
|
||||||
Assert(CS.getType()->isVectorTy(), "masked_load: must return a vector", CS);
|
Assert(CS.getType()->isVectorTy(), "masked_load: must return a vector", CS);
|
||||||
|
|
||||||
Value *Ptr = CS.getArgOperand(0);
|
Value *Ptr = CS.getArgOperand(0);
|
||||||
//Value *Alignment = CS.getArgOperand(1);
|
//Value *Alignment = CS.getArgOperand(1);
|
||||||
Value *Mask = CS.getArgOperand(2);
|
Value *Mask = CS.getArgOperand(2);
|
||||||
@ -4230,12 +4240,12 @@ void Verifier::visitIntrinsicCallSite(Intrinsic::ID ID, CallSite CS) {
|
|||||||
|
|
||||||
// DataTy is the overloaded type
|
// DataTy is the overloaded type
|
||||||
Type *DataTy = cast<PointerType>(Ptr->getType())->getElementType();
|
Type *DataTy = cast<PointerType>(Ptr->getType())->getElementType();
|
||||||
Assert(DataTy == CS.getType(),
|
Assert(DataTy == CS.getType(),
|
||||||
"masked_load: return must match pointer type", CS);
|
"masked_load: return must match pointer type", CS);
|
||||||
Assert(PassThru->getType() == DataTy,
|
Assert(PassThru->getType() == DataTy,
|
||||||
"masked_load: pass through and data type must match", CS);
|
"masked_load: pass through and data type must match", CS);
|
||||||
Assert(Mask->getType()->getVectorNumElements() ==
|
Assert(Mask->getType()->getVectorNumElements() ==
|
||||||
DataTy->getVectorNumElements(),
|
DataTy->getVectorNumElements(),
|
||||||
"masked_load: vector mask must be same length as data", CS);
|
"masked_load: vector mask must be same length as data", CS);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -4249,10 +4259,10 @@ void Verifier::visitIntrinsicCallSite(Intrinsic::ID ID, CallSite CS) {
|
|||||||
|
|
||||||
// DataTy is the overloaded type
|
// DataTy is the overloaded type
|
||||||
Type *DataTy = cast<PointerType>(Ptr->getType())->getElementType();
|
Type *DataTy = cast<PointerType>(Ptr->getType())->getElementType();
|
||||||
Assert(DataTy == Val->getType(),
|
Assert(DataTy == Val->getType(),
|
||||||
"masked_store: storee must match pointer type", CS);
|
"masked_store: storee must match pointer type", CS);
|
||||||
Assert(Mask->getType()->getVectorNumElements() ==
|
Assert(Mask->getType()->getVectorNumElements() ==
|
||||||
DataTy->getVectorNumElements(),
|
DataTy->getVectorNumElements(),
|
||||||
"masked_store: vector mask must be same length as data", CS);
|
"masked_store: vector mask must be same length as data", CS);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -204,7 +204,7 @@ define void @f34()
|
|||||||
; CHECK: define void @f34()
|
; CHECK: define void @f34()
|
||||||
{
|
{
|
||||||
call void @nobuiltin() nobuiltin
|
call void @nobuiltin() nobuiltin
|
||||||
; CHECK: call void @nobuiltin() #33
|
; CHECK: call void @nobuiltin() #34
|
||||||
ret void;
|
ret void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,6 +334,11 @@ define void @f56() writeonly
|
|||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
; CHECK: define void @f57() #33
|
||||||
|
define void @f57() speculatable {
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
; CHECK: attributes #0 = { noreturn }
|
; CHECK: attributes #0 = { noreturn }
|
||||||
; CHECK: attributes #1 = { nounwind }
|
; CHECK: attributes #1 = { nounwind }
|
||||||
; CHECK: attributes #2 = { readnone }
|
; CHECK: attributes #2 = { readnone }
|
||||||
@ -367,4 +372,5 @@ define void @f56() writeonly
|
|||||||
; CHECK: attributes #30 = { allocsize(0) }
|
; CHECK: attributes #30 = { allocsize(0) }
|
||||||
; CHECK: attributes #31 = { allocsize(0,1) }
|
; CHECK: attributes #31 = { allocsize(0,1) }
|
||||||
; CHECK: attributes #32 = { writeonly }
|
; CHECK: attributes #32 = { writeonly }
|
||||||
; CHECK: attributes #33 = { nobuiltin }
|
; CHECK: attributes #33 = { speculatable }
|
||||||
|
; CHECK: attributes #34 = { nobuiltin }
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
; Please update this file when making any IR changes. Information on the
|
; Please update this file when making any IR changes. Information on the
|
||||||
; release process for this file is available here:
|
; release process for this file is available here:
|
||||||
;
|
;
|
||||||
; http://llvm.org/docs/DeveloperPolicy.html#ir-backwards-compatibility
|
; http://llvm.org/docs/DeveloperPolicy.html#ir-backwards-compatibility
|
||||||
|
|
||||||
; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s
|
; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s
|
||||||
; RUN-PR24755: verify-uselistorder < %s
|
; RUN-PR24755: verify-uselistorder < %s
|
||||||
@ -1246,7 +1246,7 @@ exit:
|
|||||||
; CHECK: select <2 x i1> <i1 true, i1 false>, <2 x i8> <i8 2, i8 3>, <2 x i8> <i8 3, i8 2>
|
; CHECK: select <2 x i1> <i1 true, i1 false>, <2 x i8> <i8 2, i8 3>, <2 x i8> <i8 3, i8 2>
|
||||||
|
|
||||||
call void @f.nobuiltin() builtin
|
call void @f.nobuiltin() builtin
|
||||||
; CHECK: call void @f.nobuiltin() #41
|
; CHECK: call void @f.nobuiltin() #42
|
||||||
|
|
||||||
call fastcc noalias i32* @f.noalias() noinline
|
call fastcc noalias i32* @f.noalias() noinline
|
||||||
; CHECK: call fastcc noalias i32* @f.noalias() #12
|
; CHECK: call fastcc noalias i32* @f.noalias() #12
|
||||||
@ -1613,6 +1613,9 @@ normal:
|
|||||||
declare void @f.writeonly() writeonly
|
declare void @f.writeonly() writeonly
|
||||||
; CHECK: declare void @f.writeonly() #40
|
; CHECK: declare void @f.writeonly() #40
|
||||||
|
|
||||||
|
declare void @f.speculatable() speculatable
|
||||||
|
; CHECK: declare void @f.speculatable() #41
|
||||||
|
|
||||||
;; Constant Expressions
|
;; Constant Expressions
|
||||||
|
|
||||||
define i8** @constexpr() {
|
define i8** @constexpr() {
|
||||||
@ -1661,7 +1664,8 @@ define i8** @constexpr() {
|
|||||||
; CHECK: attributes #38 = { nounwind readonly }
|
; CHECK: attributes #38 = { nounwind readonly }
|
||||||
; CHECK: attributes #39 = { inaccessiblemem_or_argmemonly nounwind }
|
; CHECK: attributes #39 = { inaccessiblemem_or_argmemonly nounwind }
|
||||||
; CHECK: attributes #40 = { writeonly }
|
; CHECK: attributes #40 = { writeonly }
|
||||||
; CHECK: attributes #41 = { builtin }
|
; CHECK: attributes #41 = { speculatable }
|
||||||
|
; CHECK: attributes #42 = { builtin }
|
||||||
|
|
||||||
;; Metadata
|
;; Metadata
|
||||||
|
|
||||||
|
24
test/Verifier/speculatable-callsite-invalid.ll
Normal file
24
test/Verifier/speculatable-callsite-invalid.ll
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s
|
||||||
|
|
||||||
|
; Make sure that speculatable is not allowed on a call site if the
|
||||||
|
; declaration is not also speculatable.
|
||||||
|
|
||||||
|
declare i32 @not_speculatable()
|
||||||
|
|
||||||
|
; CHECK: speculatable attribute may not apply to call sites
|
||||||
|
; CHECK-NEXT: %ret = call i32 @not_speculatable() #0
|
||||||
|
define i32 @call_not_speculatable() {
|
||||||
|
%ret = call i32 @not_speculatable() #0
|
||||||
|
ret i32 %ret
|
||||||
|
}
|
||||||
|
|
||||||
|
@gv = internal unnamed_addr constant i32 0
|
||||||
|
|
||||||
|
; CHECK: speculatable attribute may not apply to call sites
|
||||||
|
; CHECK-NEXT: %ret = call float bitcast (i32* @gv to float ()*)() #0
|
||||||
|
define float @call_bitcast_speculatable() {
|
||||||
|
%ret = call float bitcast (i32* @gv to float()*)() #0
|
||||||
|
ret float %ret
|
||||||
|
}
|
||||||
|
|
||||||
|
attributes #0 = { speculatable }
|
20
test/Verifier/speculatable-callsite.ll
Normal file
20
test/Verifier/speculatable-callsite.ll
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
; RUN: llvm-as %s -o /dev/null
|
||||||
|
|
||||||
|
; Make sure speculatable is accepted on a call site if the declaration
|
||||||
|
; is also speculatable.
|
||||||
|
|
||||||
|
declare i32 @speculatable() #0
|
||||||
|
|
||||||
|
; Make sure this the attribute is accepted on the call site if the
|
||||||
|
; declaration matches.
|
||||||
|
define i32 @call_speculatable() {
|
||||||
|
%ret = call i32 @speculatable() #0
|
||||||
|
ret i32 %ret
|
||||||
|
}
|
||||||
|
|
||||||
|
define float @call_bitcast_speculatable() {
|
||||||
|
%ret = call float bitcast (i32()* @speculatable to float()*)() #0
|
||||||
|
ret float %ret
|
||||||
|
}
|
||||||
|
|
||||||
|
attributes #0 = { speculatable }
|
@ -123,6 +123,9 @@ struct CodeGenIntrinsic {
|
|||||||
/// True if the intrinsic is marked as convergent.
|
/// True if the intrinsic is marked as convergent.
|
||||||
bool isConvergent;
|
bool isConvergent;
|
||||||
|
|
||||||
|
// True if the intrinsic is marked as speculatable.
|
||||||
|
bool isSpeculatable;
|
||||||
|
|
||||||
enum ArgAttribute { NoCapture, Returned, ReadOnly, WriteOnly, ReadNone };
|
enum ArgAttribute { NoCapture, Returned, ReadOnly, WriteOnly, ReadNone };
|
||||||
std::vector<std::pair<unsigned, ArgAttribute>> ArgumentAttributes;
|
std::vector<std::pair<unsigned, ArgAttribute>> ArgumentAttributes;
|
||||||
|
|
||||||
|
@ -515,6 +515,7 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) {
|
|||||||
isNoReturn = false;
|
isNoReturn = false;
|
||||||
isNoDuplicate = false;
|
isNoDuplicate = false;
|
||||||
isConvergent = false;
|
isConvergent = false;
|
||||||
|
isSpeculatable = false;
|
||||||
|
|
||||||
if (DefName.size() <= 4 ||
|
if (DefName.size() <= 4 ||
|
||||||
std::string(DefName.begin(), DefName.begin() + 4) != "int_")
|
std::string(DefName.begin(), DefName.begin() + 4) != "int_")
|
||||||
@ -653,6 +654,8 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) {
|
|||||||
isConvergent = true;
|
isConvergent = true;
|
||||||
else if (Property->getName() == "IntrNoReturn")
|
else if (Property->getName() == "IntrNoReturn")
|
||||||
isNoReturn = true;
|
isNoReturn = true;
|
||||||
|
else if (Property->getName() == "IntrSpeculatable")
|
||||||
|
isSpeculatable = true;
|
||||||
else if (Property->isSubClassOf("NoCapture")) {
|
else if (Property->isSubClassOf("NoCapture")) {
|
||||||
unsigned ArgNo = Property->getValueAsInt("ArgNo");
|
unsigned ArgNo = Property->getValueAsInt("ArgNo");
|
||||||
ArgumentAttributes.push_back(std::make_pair(ArgNo, NoCapture));
|
ArgumentAttributes.push_back(std::make_pair(ArgNo, NoCapture));
|
||||||
|
@ -476,6 +476,9 @@ struct AttributeComparator {
|
|||||||
if (L->isConvergent != R->isConvergent)
|
if (L->isConvergent != R->isConvergent)
|
||||||
return R->isConvergent;
|
return R->isConvergent;
|
||||||
|
|
||||||
|
if (L->isSpeculatable != R->isSpeculatable)
|
||||||
|
return R->isSpeculatable;
|
||||||
|
|
||||||
// Try to order by readonly/readnone attribute.
|
// Try to order by readonly/readnone attribute.
|
||||||
CodeGenIntrinsic::ModRefBehavior LK = L->ModRef;
|
CodeGenIntrinsic::ModRefBehavior LK = L->ModRef;
|
||||||
CodeGenIntrinsic::ModRefBehavior RK = R->ModRef;
|
CodeGenIntrinsic::ModRefBehavior RK = R->ModRef;
|
||||||
@ -600,7 +603,7 @@ void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints,
|
|||||||
if (!intrinsic.canThrow ||
|
if (!intrinsic.canThrow ||
|
||||||
intrinsic.ModRef != CodeGenIntrinsic::ReadWriteMem ||
|
intrinsic.ModRef != CodeGenIntrinsic::ReadWriteMem ||
|
||||||
intrinsic.isNoReturn || intrinsic.isNoDuplicate ||
|
intrinsic.isNoReturn || intrinsic.isNoDuplicate ||
|
||||||
intrinsic.isConvergent) {
|
intrinsic.isConvergent || intrinsic.isSpeculatable) {
|
||||||
OS << " const Attribute::AttrKind Atts[] = {";
|
OS << " const Attribute::AttrKind Atts[] = {";
|
||||||
bool addComma = false;
|
bool addComma = false;
|
||||||
if (!intrinsic.canThrow) {
|
if (!intrinsic.canThrow) {
|
||||||
@ -625,6 +628,12 @@ void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints,
|
|||||||
OS << "Attribute::Convergent";
|
OS << "Attribute::Convergent";
|
||||||
addComma = true;
|
addComma = true;
|
||||||
}
|
}
|
||||||
|
if (intrinsic.isSpeculatable) {
|
||||||
|
if (addComma)
|
||||||
|
OS << ",";
|
||||||
|
OS << "Attribute::Speculatable";
|
||||||
|
addComma = true;
|
||||||
|
}
|
||||||
|
|
||||||
switch (intrinsic.ModRef) {
|
switch (intrinsic.ModRef) {
|
||||||
case CodeGenIntrinsic::NoMem:
|
case CodeGenIntrinsic::NoMem:
|
||||||
|
Loading…
Reference in New Issue
Block a user