1
0
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:
Matt Arsenault 2017-04-28 20:25:27 +00:00
parent 61aeea9876
commit c9972a05d5
19 changed files with 133 additions and 18 deletions

View File

@ -1535,6 +1535,17 @@ example:
``sanitize_thread``
This attribute indicates that ThreadSanitizer checks
(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``
This attribute indicates that the function should emit a stack
smashing protector. It is in the form of a "canary" --- a random value

View File

@ -545,7 +545,8 @@ enum AttributeKindCodes {
ATTR_KIND_INACCESSIBLEMEM_ONLY = 49,
ATTR_KIND_INACCESSIBLEMEM_OR_ARGMEMONLY = 50,
ATTR_KIND_ALLOC_SIZE = 51,
ATTR_KIND_WRITEONLY = 52
ATTR_KIND_WRITEONLY = 52,
ATTR_KIND_SPECULATABLE = 53
};
enum ComdatSelectionKindCodes {

View File

@ -137,6 +137,9 @@ def SExt : EnumAttr<"signext">;
/// +1 bias 0 means unaligned (different from alignstack=(1)).
def StackAlignment : EnumAttr<"alignstack">;
/// Function can be speculated.
def Speculatable : EnumAttr<"speculatable">;
/// Stack protection.
def StackProtect : EnumAttr<"ssp">;

View File

@ -418,6 +418,14 @@ public:
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
/// indirectly.
bool doesNotRecurse() const {

View File

@ -98,6 +98,9 @@ def IntrNoDuplicate : IntrinsicProperty;
// Parallels the convergent attribute on LLVM IR functions.
def IntrConvergent : IntrinsicProperty;
// This property indicates that the intrinsic is safe to speculate.
def IntrSpeculatable : IntrinsicProperty;
//===----------------------------------------------------------------------===//
// Types used by intrinsics.
//===----------------------------------------------------------------------===//

View File

@ -648,6 +648,7 @@ lltok::Kind LLLexer::LexIdentifier() {
KEYWORD(returned);
KEYWORD(returns_twice);
KEYWORD(signext);
KEYWORD(speculatable);
KEYWORD(sret);
KEYWORD(ssp);
KEYWORD(sspreq);

View File

@ -1095,6 +1095,7 @@ bool LLParser::ParseFnAttributeValuePairs(AttrBuilder &B,
case lltok::kw_readonly: B.addAttribute(Attribute::ReadOnly); break;
case lltok::kw_returns_twice:
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_sspreq: B.addAttribute(Attribute::StackProtectReq); break;
case lltok::kw_sspstrong:

View File

@ -198,6 +198,7 @@ enum Kind {
kw_returned,
kw_returns_twice,
kw_signext,
kw_speculatable,
kw_ssp,
kw_sspreq,
kw_sspstrong,

View File

@ -1119,6 +1119,7 @@ static uint64_t getRawAttributeMask(Attribute::AttrKind Val) {
case Attribute::SwiftSelf: return 1ULL << 51;
case Attribute::SwiftError: return 1ULL << 52;
case Attribute::WriteOnly: return 1ULL << 53;
case Attribute::Speculatable: return 1ULL << 54;
case Attribute::Dereferenceable:
llvm_unreachable("dereferenceable attribute not supported in raw format");
break;
@ -1315,6 +1316,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
return Attribute::ReturnsTwice;
case bitc::ATTR_KIND_S_EXT:
return Attribute::SExt;
case bitc::ATTR_KIND_SPECULATABLE:
return Attribute::Speculatable;
case bitc::ATTR_KIND_STACK_ALIGNMENT:
return Attribute::StackAlignment;
case bitc::ATTR_KIND_STACK_PROTECT:

View File

@ -688,6 +688,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
return bitc::ATTR_KIND_RETURNS_TWICE;
case Attribute::SExt:
return bitc::ATTR_KIND_S_EXT;
case Attribute::Speculatable:
return bitc::ATTR_KIND_SPECULATABLE;
case Attribute::StackAlignment:
return bitc::ATTR_KIND_STACK_ALIGNMENT;
case Attribute::StackProtect:

View File

@ -315,6 +315,8 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
return "returns_twice";
if (hasAttribute(Attribute::SExt))
return "signext";
if (hasAttribute(Attribute::Speculatable))
return "speculatable";
if (hasAttribute(Attribute::StackProtect))
return "ssp";
if (hasAttribute(Attribute::StackProtectReq))

View File

@ -1352,6 +1352,7 @@ static bool isFuncOnlyAttr(Attribute::AttrKind Kind) {
case Attribute::InaccessibleMemOnly:
case Attribute::InaccessibleMemOrArgMemOnly:
case Attribute::AllocSize:
case Attribute::Speculatable:
return true;
default:
break;
@ -2610,6 +2611,15 @@ void Verifier::verifyCallSite(CallSite CS) {
Assert(verifyAttributeCount(Attrs, CS.arg_size()),
"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.
verifyFunctionAttrs(FTy, Attrs, I);

View File

@ -204,7 +204,7 @@ define void @f34()
; CHECK: define void @f34()
{
call void @nobuiltin() nobuiltin
; CHECK: call void @nobuiltin() #33
; CHECK: call void @nobuiltin() #34
ret void;
}
@ -334,6 +334,11 @@ define void @f56() writeonly
ret void
}
; CHECK: define void @f57() #33
define void @f57() speculatable {
ret void
}
; CHECK: attributes #0 = { noreturn }
; CHECK: attributes #1 = { nounwind }
; CHECK: attributes #2 = { readnone }
@ -367,4 +372,5 @@ define void @f56() writeonly
; CHECK: attributes #30 = { allocsize(0) }
; CHECK: attributes #31 = { allocsize(0,1) }
; CHECK: attributes #32 = { writeonly }
; CHECK: attributes #33 = { nobuiltin }
; CHECK: attributes #33 = { speculatable }
; CHECK: attributes #34 = { nobuiltin }

View File

@ -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>
call void @f.nobuiltin() builtin
; CHECK: call void @f.nobuiltin() #41
; CHECK: call void @f.nobuiltin() #42
call fastcc noalias i32* @f.noalias() noinline
; CHECK: call fastcc noalias i32* @f.noalias() #12
@ -1613,6 +1613,9 @@ normal:
declare void @f.writeonly() writeonly
; CHECK: declare void @f.writeonly() #40
declare void @f.speculatable() speculatable
; CHECK: declare void @f.speculatable() #41
;; Constant Expressions
define i8** @constexpr() {
@ -1661,7 +1664,8 @@ define i8** @constexpr() {
; CHECK: attributes #38 = { nounwind readonly }
; CHECK: attributes #39 = { inaccessiblemem_or_argmemonly nounwind }
; CHECK: attributes #40 = { writeonly }
; CHECK: attributes #41 = { builtin }
; CHECK: attributes #41 = { speculatable }
; CHECK: attributes #42 = { builtin }
;; Metadata

View 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 }

View 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 }

View File

@ -123,6 +123,9 @@ struct CodeGenIntrinsic {
/// True if the intrinsic is marked as convergent.
bool isConvergent;
// True if the intrinsic is marked as speculatable.
bool isSpeculatable;
enum ArgAttribute { NoCapture, Returned, ReadOnly, WriteOnly, ReadNone };
std::vector<std::pair<unsigned, ArgAttribute>> ArgumentAttributes;

View File

@ -515,6 +515,7 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) {
isNoReturn = false;
isNoDuplicate = false;
isConvergent = false;
isSpeculatable = false;
if (DefName.size() <= 4 ||
std::string(DefName.begin(), DefName.begin() + 4) != "int_")
@ -653,6 +654,8 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) {
isConvergent = true;
else if (Property->getName() == "IntrNoReturn")
isNoReturn = true;
else if (Property->getName() == "IntrSpeculatable")
isSpeculatable = true;
else if (Property->isSubClassOf("NoCapture")) {
unsigned ArgNo = Property->getValueAsInt("ArgNo");
ArgumentAttributes.push_back(std::make_pair(ArgNo, NoCapture));

View File

@ -476,6 +476,9 @@ struct AttributeComparator {
if (L->isConvergent != R->isConvergent)
return R->isConvergent;
if (L->isSpeculatable != R->isSpeculatable)
return R->isSpeculatable;
// Try to order by readonly/readnone attribute.
CodeGenIntrinsic::ModRefBehavior LK = L->ModRef;
CodeGenIntrinsic::ModRefBehavior RK = R->ModRef;
@ -600,7 +603,7 @@ void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints,
if (!intrinsic.canThrow ||
intrinsic.ModRef != CodeGenIntrinsic::ReadWriteMem ||
intrinsic.isNoReturn || intrinsic.isNoDuplicate ||
intrinsic.isConvergent) {
intrinsic.isConvergent || intrinsic.isSpeculatable) {
OS << " const Attribute::AttrKind Atts[] = {";
bool addComma = false;
if (!intrinsic.canThrow) {
@ -625,6 +628,12 @@ void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints,
OS << "Attribute::Convergent";
addComma = true;
}
if (intrinsic.isSpeculatable) {
if (addComma)
OS << ",";
OS << "Attribute::Speculatable";
addComma = true;
}
switch (intrinsic.ModRef) {
case CodeGenIntrinsic::NoMem: