Skip to content

Commit b35f5bc

Browse files
committed
Distinguish between enum and string attributes
1 parent f7116ab commit b35f5bc

File tree

1 file changed

+139
-25
lines changed

1 file changed

+139
-25
lines changed

Sources/LLVM/Function+Attributes.swift

Lines changed: 139 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
import cllvm
33
#endif
44

5-
/// Enumerates the attributes of LLVM functions and function parameters.
6-
public enum FunctionAttribute: String {
5+
/// Enumerates the kinds of attributes of LLVM functions and function parameters.
6+
public enum AttributeKind: String {
77
/// This attribute indicates that, when emitting the prologue and epilogue,
88
/// the backend should forcibly align the stack pointer.
99
case alignstack
@@ -81,13 +81,6 @@ public enum FunctionAttribute: String {
8181
/// otherwise do optimizations specifically to reduce code size as long as
8282
/// they do not significantly impact runtime performance.
8383
case optsize
84-
/// This attribute tells the code generator that the code generated for this
85-
/// function needs to follow certain conventions that make it possible for a
86-
/// runtime function to patch over it later.
87-
case patchableFunction = "patchable-function"
88-
/// This attribute indicates that the function will trigger a guard region in
89-
/// the end of the stack.
90-
case probeStack = "probe-stack"
9184
/// This attribute indicates that the function computes its result (or
9285
/// decides to unwind an exception) based strictly on its arguments, without
9386
/// dereferencing any pointer arguments or otherwise accessing any mutable
@@ -97,11 +90,6 @@ public enum FunctionAttribute: String {
9790
/// pointer arguments (including byval arguments) or otherwise modify any
9891
/// state (e.g. memory, control registers, etc) visible to caller functions.
9992
case readonly
100-
/// This attribute controls the behavior of stack probes: either the
101-
/// "probe-stack" attribute, or ABI-required stack probes, if any.
102-
case stackProbleSize = "stack-probe-size"
103-
/// This attribute disables ABI-required stack probes, if any.
104-
case noStackArgProbe = "no-stack-arg-probe"
10593
/// This attribute indicates that the function may write to but does not read
10694
/// read from memory.
10795
case writeonly
@@ -142,9 +130,6 @@ public enum FunctionAttribute: String {
142130
/// This attribute indicates that the function was called from a scope that
143131
/// requires strict floating point semantics.
144132
case strictfp
145-
/// This attribute indicates that the function will delegate to some other
146-
/// function with a tail call.
147-
case thunk
148133
/// This attribute indicates that the ABI being targeted requires that an
149134
/// unwind table entry be produced for this function even if we can show
150135
/// that no exceptions passes by it.
@@ -201,7 +186,7 @@ public enum FunctionAttribute: String {
201186
case swifterror
202187

203188
/// ID of the attribute.
204-
internal var kindID: UInt32 {
189+
internal var id: UInt32 {
205190
return LLVMGetEnumAttributeKindForName(rawValue, rawValue.count)
206191
}
207192
}
@@ -236,25 +221,154 @@ public enum AttributeIndex: ExpressibleByIntegerLiteral, RawRepresentable {
236221
}
237222
}
238223

224+
/// An LLVM attribute.
225+
public protocol Attribute {
226+
var name: String { get }
227+
func asLLVM() -> LLVMAttributeRef
228+
}
229+
230+
/// An "enum" (a.k.a. target-independent) attribute.
231+
public struct EnumAttribute: Attribute {
232+
internal let llvm: LLVMAttributeRef
233+
internal init(llvm: LLVMAttributeRef) {
234+
self.llvm = llvm
235+
}
236+
237+
/// The kind ID of the attribute.
238+
internal var kindID: UInt32 {
239+
return LLVMGetEnumAttributeKind(llvm)
240+
}
241+
242+
/// The name of the attribute's kind.
243+
public var name: String {
244+
return ""
245+
}
246+
247+
/// The value of the attribute.
248+
public var value: UInt64 {
249+
return LLVMGetEnumAttributeValue(llvm)
250+
}
251+
252+
/// Retrieves the underlying LLVM attribute object.
253+
public func asLLVM() -> LLVMAttributeRef {
254+
return llvm
255+
}
256+
}
257+
258+
/// A "string" (a.k.a. target-dependent) attribute.
259+
public struct StringAttribute: Attribute {
260+
internal let llvm: LLVMAttributeRef
261+
internal init(llvm: LLVMAttributeRef) {
262+
self.llvm = llvm
263+
}
264+
265+
/// The name of the attribute.
266+
public var name: String {
267+
var length: UInt32 = 0
268+
let cstring = LLVMGetStringAttributeKind(llvm, &length)
269+
return String.init(cString: cstring!)
270+
}
271+
272+
/// The value of the attribute.
273+
public var value: String {
274+
var length: UInt32 = 0
275+
let cstring = LLVMGetStringAttributeValue(llvm, &length)
276+
return String.init(cString: cstring!)
277+
}
278+
279+
/// Retrieves the underlying LLVM attribute object.
280+
public func asLLVM() -> LLVMAttributeRef {
281+
return llvm
282+
}
283+
}
284+
239285
extension Function {
240-
/// Adds an attribute to the function, its return value or its parameters.
286+
/// Adds an enum attribute to the function, its return value or one of its
287+
/// parameters.
241288
///
242-
/// - parameter attr: The attribute to add.
289+
/// - parameter attrKind: The kind of the attribute to add.
243290
/// - parameter value: The optional value of the attribute.
244291
/// - parameter index: The index representing the function, its return value
245292
/// or one of its parameters.
246-
public func addAttribute(_ attr: FunctionAttribute, value: UInt64 = 0, to index: AttributeIndex) {
293+
@discardableResult
294+
public func addAttribute(_ attrKind: AttributeKind, value: UInt64 = 0, to index: AttributeIndex) -> EnumAttribute {
247295
let ctx = LLVMGetModuleContext(LLVMGetGlobalParent(llvm))
248-
let attrRef = LLVMCreateEnumAttribute(ctx, attr.kindID, value)
296+
let attrRef = LLVMCreateEnumAttribute(ctx, attrKind.id, value)
249297
LLVMAddAttributeAtIndex(llvm, index.rawValue, attrRef)
298+
return EnumAttribute(llvm: attrRef!)
250299
}
251300

252-
/// Removes an attribute from the function.
301+
/// Adds a string attribute to the function, its return value or one of its
302+
/// parameters.
303+
///
304+
/// - parameter name: The name of the attribute to add.
305+
/// - parameter value: The optional value of the attribute.
306+
/// - parameter index: The index representing the function, its return value
307+
/// or one of its parameters.
308+
@discardableResult
309+
public func addAttribute(_ name: String, value: String = "", to index: AttributeIndex) -> StringAttribute {
310+
let ctx = LLVMGetModuleContext(LLVMGetGlobalParent(llvm))
311+
let attrRef = name.withCString { cname -> LLVMAttributeRef! in
312+
return value.withCString { cvalue in
313+
return LLVMCreateStringAttribute(ctx, cname, UInt32(name.count), cvalue, UInt32(value.count))
314+
}
315+
}
316+
LLVMAddAttributeAtIndex(llvm, index.rawValue, attrRef)
317+
return StringAttribute(llvm: attrRef!)
318+
}
319+
320+
/// Removes an attribute from the function, its return value or one of its
321+
/// parameters.
253322
///
254323
/// - parameter attr: The attribute to remove.
255324
/// - parameter index: The index representing the function, its return value
256325
/// or one of its parameters.
257-
public func removeAttribute(_ attr: FunctionAttribute, value: UInt64 = 0, from index: AttributeIndex) {
258-
LLVMRemoveEnumAttributeAtIndex(llvm, index.rawValue, attr.kindID)
326+
public func removeAttribute(_ attr: Attribute, from index: AttributeIndex) {
327+
switch attr {
328+
case let enumAttr as EnumAttribute:
329+
LLVMRemoveEnumAttributeAtIndex(llvm, index.rawValue, enumAttr.kindID)
330+
case let stringAttr as StringAttribute:
331+
var length: UInt32 = 0
332+
let cstring = LLVMGetStringAttributeKind(stringAttr.llvm, &length)
333+
LLVMRemoveStringAttributeAtIndex(llvm, index.rawValue, cstring, length)
334+
default:
335+
fatalError()
336+
}
337+
}
338+
339+
/// Removes an enum attribute from the function, its return value or one of
340+
/// its parameters.
341+
///
342+
/// - parameter attr: The kind of the attribute to remove.
343+
/// - parameter index: The index representing the function, its return value
344+
/// or one of its parameters.
345+
public func removeAttribute(_ attrKind: AttributeKind, from index: AttributeIndex) {
346+
LLVMRemoveEnumAttributeAtIndex(llvm, index.rawValue, attrKind.id)
347+
}
348+
349+
/// Removes a string attribute from the function, its return value or one of
350+
/// its parameters.
351+
///
352+
/// - parameter name: The name of the attribute to remove.
353+
/// - parameter index: The index representing the function, its return value
354+
/// or one of its parameters.
355+
public func removeAttribute(_ name: String, from index: AttributeIndex) {
356+
name.withCString {
357+
LLVMRemoveStringAttributeAtIndex(llvm, index.rawValue, $0, UInt32(name.count))
358+
}
359+
}
360+
361+
/// Gets the attributes of the function, its return value or its parameters.
362+
public func attributes(at index: AttributeIndex) -> [Attribute] {
363+
let attrCount = LLVMGetAttributeCountAtIndex(llvm, index.rawValue)
364+
var attrRefs: [LLVMAttributeRef?] = Array(repeating: nil, count: Int(attrCount))
365+
LLVMGetAttributesAtIndex(llvm, index.rawValue, &attrRefs)
366+
return attrRefs.map { attrRef -> Attribute in
367+
if LLVMIsEnumAttribute(attrRef) != 0 {
368+
return EnumAttribute(llvm: attrRef!)
369+
} else {
370+
return StringAttribute(llvm: attrRef!)
371+
}
372+
}
259373
}
260374
}

0 commit comments

Comments
 (0)