-
Notifications
You must be signed in to change notification settings - Fork 57
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Wrap LLVMAttributeRef API #126
Conversation
public func addAttribute(_ attr: FunctionAttribute, value: UInt64 = 0) { | ||
let ctx = LLVMGetModuleContext(LLVMGetGlobalParent(llvm)) | ||
let attrRef = LLVMCreateEnumAttribute(ctx, attr.kindID, value) | ||
LLVMAddAttributeAtIndex(llvm, 0, attrRef) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not correct. This is the index for the return value of the function.
/// - parameterIndex: The index of the parameter to which add the | ||
/// attribute, starting from 0. | ||
public func addParameterAttribute(_ attr: ParameterAttribute, value: UInt64 = 0, | ||
for parameterIndex: LLVMAttributeIndex) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have a policy of never exposing LLVM's types to the user. I have an idea of how we can lift this into an enum in one case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use Int
here.
I think we can kill two birds with one stone here by lifting enum AttributeIndex: UInt32 {
case returnValue // 0
case function // ~0
} The |
#endif | ||
|
||
/// Enumerates the attributes of LLVM functions. | ||
public enum FunctionAttribute: String { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for documenting this patch.
Do you know if |
/// This attribute indicates that the function may only access memory that is | ||
/// either not accessible by the module being compiled, or is pointed to by | ||
/// its pointer arguments. | ||
case inaccessiblemem_or_argmemonly |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All the snake_case
should be camelCase
.
Oh, it'd also be great if you could add a test. It can be as simple as a loop that adds/removes All The Attributes to a dummy function and its parameters and checks that they got registered/remoed. |
Thanks for the feedbacks! A few comments on the changes I made: According to LLVM docs, I understand there are several kinds of attributes in LLVM's new scheme. If I understand the docs correctly, this is also where the distinction between attributes specified with or without quotes comes in. The formers describe target-independent attributes, while the latters describe dependent ones. Therefore I took the liberty to create two types to distinguish between those two kind of attributes. I wrapped all I implemented a method to retrieve the attributes from a function. I made the choice to return an array rather than a set, so as to avoid having to conform to I wrote some tests for all these shenanigans. Those revealed that there seems to be a problem with the removal of valued enum attributes. I tried to understand what's causing this bug within LLVM's source, but I have to admit to find the whole thing quite puzzling. Indeed, removing an integer attribute seems to always fail, because AttributeSet AttributeSet::removeAttribute(LLVMContext &C,
Attribute::AttrKind Kind) const {
if (!hasAttribute(Kind)) return *this;
AttrBuilder B;
B.addAttribute(Kind);
return removeAttributes(C, B);
} This in turn fails in AttrBuilder &AttrBuilder::addAttribute(Attribute::AttrKind Val) {
assert((unsigned)Val < Attribute::EndAttrKinds && "Attribute out of range!");
assert(Val != Attribute::Alignment && Val != Attribute::StackAlignment &&
Val != Attribute::Dereferenceable && Val != Attribute::AllocSize &&
"Adding integer attribute without adding a value!");
Attrs[Val] = true;
return *this;
} Maybe an issue with my version of LLVM ... |
I confirm the bug about valued enum attributes removal is caused by LLVM: [Attributes] Fix crash when attempting to remove alignment from an attribute list/set. |
|
||
/// The name of the attribute's kind. | ||
public var name: String { | ||
return "" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we can't provide this then we should omit it.
} | ||
|
||
/// An LLVM attribute. | ||
public protocol Attribute { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you document this and its members a little more
let cstring = LLVMGetStringAttributeKind(stringAttr.llvm, &length) | ||
LLVMRemoveStringAttributeAtIndex(llvm, index.rawValue, cstring, length) | ||
default: | ||
fatalError() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add an explanation string to this fatal error
Down to nits. This is looking quite good. |
What would be the best thing to do about the issue with |
If we can't safely provide this API then we shouldn't provide it altogether. We can hold out until 7.0 and leave behind a note. I'd much rather that than crashing deep in LLVM. |
What I would recommend is we bake the guard into the API and fatal error with an explanation as to why we cannot safely remove the attribute yet. |
Is there any way we can know what version of LLVM we're linked to? |
|
Alright, I'd make the guard only for the attributes that may fail, namely |
The current version of LLVM crashes when attempting to remove valued enum attributes. The bug was discovered and fixed in LLVM 7 (see llvm-mirror/llvm@9bc0b10). The guard placed in `removeAttribute` should be removed once this version is released.
Excellent. Thank you kindly. ⛵️ |
Disclaimer: I'm quite a newbie with LLVM
This is my attempt at wrapping the LLVM 4.0.0+
LLVMAttributeRef
API (as mentioned in #10).I extracted the list of parameters from LLVM's docs. I didn't make any unit tests so far, and haven't tested all parameters.
Due to my limited knowledge of LLVM, I'm unsure of the expected result of calling
LLVMAddAttributeAtIndex
on parameters whose arguments aren't a single integer value (e.g.allocsize
), nor of the difference between attributes specified with or without quote in the documentation (e.g."patchable-function"
). Some review from a more experienced developer would be greatly appreciated.I tried to follow the coding convention I could guess from the existing code to the best of my ability, but don't hesitate to comment on that as well.