Skip to content

Commit a9581c7

Browse files
authored
Merge pull request #126 from kyouko-taiga/llvmattributeref-api
Wrap LLVMAttributeRef API
2 parents adc94d2 + ee76920 commit a9581c7

File tree

2 files changed

+649
-0
lines changed

2 files changed

+649
-0
lines changed
+385
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,385 @@
1+
#if SWIFT_PACKAGE
2+
import cllvm
3+
#endif
4+
5+
/// Enumerates the kinds of attributes of LLVM functions and function parameters.
6+
public enum AttributeKind: String {
7+
/// This attribute indicates that, when emitting the prologue and epilogue,
8+
/// the backend should forcibly align the stack pointer.
9+
case alignstack
10+
/// This attribute indicates that the annotated function will always return
11+
/// at least a given number of bytes (or null).
12+
case allocsize
13+
/// This attribute indicates that the inliner should attempt to inline this
14+
/// function into callers whenever possible, ignoring any active inlining
15+
/// size threshold for this caller.
16+
case alwaysinline
17+
/// This indicates that the callee function at a call site should be
18+
/// recognized as a built-in function, even though the function’s declaration
19+
/// uses the nobuiltin attribute
20+
case builtin
21+
/// This attribute indicates that this function is rarely called.
22+
case cold
23+
/// In some parallel execution models, there exist operations that cannot be
24+
/// made control-dependent on any additional values.
25+
case convergent
26+
/// This attribute indicates that the function may only access memory that is
27+
/// not accessible by the module being compiled.
28+
case inaccessiblememonly
29+
/// This attribute indicates that the function may only access memory that is
30+
/// either not accessible by the module being compiled, or is pointed to by
31+
/// its pointer arguments.
32+
case inaccessiblememOrArgmemonly = "inaccessiblemem_or_argmemonly"
33+
/// This attribute indicates that the source code contained a hint that inlin
34+
/// inlining this function is desirable (such as the “inline” keyword in
35+
/// C/C++).
36+
case inlinehint
37+
/// This attribute indicates that the function should be added to a
38+
/// jump-instruction table at code-generation time, and that all
39+
/// address-taken references to this function should be replaced with a
40+
/// reference to the appropriate jump-instruction-table function pointer.
41+
case jumptable
42+
/// This attribute suggests that optimization passes and code generator
43+
/// passes make choices that keep the code size of this function as small as
44+
/// possible and perform optimizations that may sacrifice runtime performance
45+
/// in order to minimize the size of the generated code.
46+
case minsize
47+
/// This attribute disables prologue / epilogue emission for the function.
48+
case naked
49+
/// When this attribute is set to true, the jump tables and lookup tables
50+
/// that can be generated from a switch case lowering are disabled.
51+
case noJumpTables = "no-jump-tables"
52+
/// This indicates that the callee function at a call site is not recognized
53+
/// as a built-in function.
54+
case nobuiltin
55+
/// This attribute indicates that calls to the function cannot be duplicated.
56+
case noduplicate
57+
/// This attributes disables implicit floating point instructions.
58+
case noimplicitfloat
59+
/// This attribute indicates that the inliner should never inline this
60+
/// function in any situation.
61+
case noinline
62+
/// This attribute suppresses lazy symbol binding for the function.
63+
case nonlazybind
64+
/// This attribute indicates that the code generator should not use a red
65+
/// zone, even if the target-specific ABI normally permits it.
66+
case noredzone
67+
/// This function attribute indicates that the function never returns
68+
/// normally.
69+
case noreturn
70+
/// This function attribute indicates that the function does not call itself
71+
/// either directly or indirectly down any possible call path.
72+
case norecurse
73+
/// This function attribute indicates that the function never raises an
74+
/// exception.
75+
case nounwind
76+
/// This function attribute indicates that most optimization passes will skip
77+
/// this function, with the exception of interprocedural optimization passes.
78+
case optnone
79+
/// This attribute suggests that optimization passes and code generator
80+
/// passes make choices that keep the code size of this function low, and
81+
/// otherwise do optimizations specifically to reduce code size as long as
82+
/// they do not significantly impact runtime performance.
83+
case optsize
84+
/// This attribute indicates that the function computes its result (or
85+
/// decides to unwind an exception) based strictly on its arguments, without
86+
/// dereferencing any pointer arguments or otherwise accessing any mutable
87+
/// state (e.g. memory, control registers, etc) visible to caller functions.
88+
case readnone
89+
/// This attribute indicates that the function does not write through any
90+
/// pointer arguments (including byval arguments) or otherwise modify any
91+
/// state (e.g. memory, control registers, etc) visible to caller functions.
92+
case readonly
93+
/// This attribute indicates that the function may write to but does not read
94+
/// read from memory.
95+
case writeonly
96+
/// This attribute indicates that the only memory accesses inside function
97+
/// are loads and stores from objects pointed to by its pointer-typed
98+
/// arguments, with arbitrary offsets.
99+
case argmemonly
100+
/// This attribute indicates that this function can return twice.
101+
case returnsTwice = "returns_twice"
102+
/// This attribute indicates that SafeStack protection is enabled for this
103+
/// function.
104+
case safestack
105+
/// This attribute indicates that AddressSanitizer checks (dynamic address
106+
/// safety analysis) are enabled for this function.
107+
case sanitizeAddress = "sanitize_address"
108+
/// This attribute indicates that MemorySanitizer checks (dynamic detection
109+
/// of accesses to uninitialized memory) are enabled for this function.
110+
case sanitizeMemory = "sanitize_memory"
111+
/// This attribute indicates that ThreadSanitizer checks (dynamic thread
112+
/// safety analysis) are enabled for this function.
113+
case sanitizeThread = "sanitize_thread"
114+
/// This attribute indicates that HWAddressSanitizer checks (dynamic address
115+
/// safety analysis based on tagged pointers) are enabled for this function.
116+
case sanitizeHWAddress = "sanitize_hwaddress"
117+
/// This function attribute indicates that the function does not have any
118+
/// effects besides calculating its result and does not have undefined
119+
/// behavior.
120+
case speculatable
121+
/// This attribute indicates that the function should emit a stack smashing
122+
/// protector.
123+
case ssp
124+
/// This attribute indicates that the function should always emit a stack
125+
/// smashing protector
126+
case sspreq
127+
/// This attribute indicates that the function should emit a stack smashing
128+
/// protector.
129+
case sspstrong
130+
/// This attribute indicates that the function was called from a scope that
131+
/// requires strict floating point semantics.
132+
case strictfp
133+
/// This attribute indicates that the ABI being targeted requires that an
134+
/// unwind table entry be produced for this function even if we can show
135+
/// that no exceptions passes by it.
136+
case uwtable
137+
/// This indicates to the code generator that the parameter or return value
138+
/// should be zero-extended to the extent required by the target’s ABI by the
139+
/// caller (for a parameter) or the callee (for a return value).
140+
case zeroext
141+
/// This indicates to the code generator that the parameter or return value
142+
/// should be sign-extended to the extent required by the target’s ABI (which
143+
/// is usually 32-bits) by the caller (for a parameter) or the callee (for a
144+
/// return value).
145+
case signext
146+
/// This indicates that this parameter or return value should be treated in a
147+
/// special target-dependent fashion while emitting code for a function call
148+
/// or return.
149+
case inreg
150+
/// This indicates that the pointer parameter should really be passed by
151+
/// value to the function.
152+
case byval
153+
/// The inalloca argument attribute allows the caller to take the address of
154+
/// outgoing stack arguments
155+
case inalloca
156+
/// This indicates that the pointer parameter specifies the address of a
157+
/// structure that is the return value of the function in the source program.
158+
case sret
159+
/// This indicates that the pointer value may be assumed by the optimizer to
160+
/// have the specified alignment.
161+
case align
162+
/// This indicates that objects accessed via pointer values based on the
163+
/// argument or return value are not also accessed, during the execution of
164+
/// the function, via pointer values not based on the argument or return
165+
/// value.
166+
case noalias
167+
/// This indicates that the callee does not make any copies of the pointer
168+
/// that outlive the callee itself.
169+
case nocapture
170+
/// This indicates that the pointer parameter can be excised using the
171+
/// trampoline intrinsics.
172+
case nest
173+
/// This indicates that the function always returns the argument as its
174+
/// return value.
175+
case returned
176+
/// This indicates that the parameter or return pointer is not null.
177+
case nonnull
178+
/// This indicates that the parameter or return pointer is dereferenceable.
179+
case dereferenceable
180+
/// This indicates that the parameter or return value isn’t both non-null and
181+
/// non-dereferenceable (up to `n` bytes) at the same time.
182+
case dereferenceableOrNull = "dereferenceable_or_null"
183+
/// This indicates that the parameter is the self/context parameter.
184+
case swiftself
185+
/// This attribute is motivated to model and optimize Swift error handling.
186+
case swifterror
187+
188+
/// ID of the attribute.
189+
internal var id: UInt32 {
190+
return LLVMGetEnumAttributeKindForName(rawValue, rawValue.count)
191+
}
192+
}
193+
194+
/// Represents the possible indices of function attributes.
195+
public enum AttributeIndex: ExpressibleByIntegerLiteral, RawRepresentable {
196+
/// Represents the function itself.
197+
case function
198+
/// Represents the function's return value.
199+
case returnValue
200+
/// Represents the function's i-th argument.
201+
case argument(Int)
202+
203+
public init(integerLiteral value: UInt32) {
204+
switch value {
205+
case ~0: self = .function
206+
case 0: self = .returnValue
207+
default: self = .argument(Int(value) - 1)
208+
}
209+
}
210+
211+
public init?(rawValue: RawValue) {
212+
self.init(integerLiteral: rawValue)
213+
}
214+
215+
public var rawValue: UInt32 {
216+
switch self {
217+
case .function: return ~0
218+
case .returnValue: return 0
219+
case .argument(let i): return UInt32(i) + 1
220+
}
221+
}
222+
}
223+
224+
/// An LLVM attribute.
225+
///
226+
/// Functions, return types and each parameter may have a set of attributes
227+
/// associated with them. Such attributes are used to communicate additional
228+
/// information about a function. Attributes are considered to be part of the
229+
/// function, but not of the function type.
230+
public protocol Attribute {
231+
/// Retrieves the underlying LLVM attribute reference object.
232+
func asLLVM() -> LLVMAttributeRef
233+
}
234+
235+
/// An "enum" (a.k.a. target-independent) attribute.
236+
public struct EnumAttribute: Attribute {
237+
internal let llvm: LLVMAttributeRef
238+
internal init(llvm: LLVMAttributeRef) {
239+
self.llvm = llvm
240+
}
241+
242+
/// The kind ID of the attribute.
243+
internal var kindID: UInt32 {
244+
return LLVMGetEnumAttributeKind(llvm)
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+
285+
extension Function {
286+
/// Adds an enum attribute to the function, its return value or one of its
287+
/// parameters.
288+
///
289+
/// - parameter attrKind: The kind of the attribute to add.
290+
/// - parameter value: The optional value of the attribute.
291+
/// - parameter index: The index representing the function, its return value
292+
/// or one of its parameters.
293+
@discardableResult
294+
public func addAttribute(_ attrKind: AttributeKind, value: UInt64 = 0, to index: AttributeIndex) -> EnumAttribute {
295+
let ctx = LLVMGetModuleContext(LLVMGetGlobalParent(llvm))
296+
let attrRef = LLVMCreateEnumAttribute(ctx, attrKind.id, value)
297+
LLVMAddAttributeAtIndex(llvm, index.rawValue, attrRef)
298+
return EnumAttribute(llvm: attrRef!)
299+
}
300+
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.
322+
///
323+
/// - parameter attr: The attribute to remove.
324+
/// - parameter index: The index representing the function, its return value
325+
/// or one of its parameters.
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("unexpected attribute type")
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+
// FIXME: Remove when LLVM 7.0.0 is released.
347+
guard attrKind != .align
348+
&& attrKind != .alignstack
349+
&& attrKind != .allocsize
350+
&& attrKind != .dereferenceable
351+
&& attrKind != .dereferenceableOrNull else {
352+
fatalError(
353+
"Removing valued enum attributes crashes in LLVM <7.0.0 " +
354+
"and is currently disabled in LLVMSwift.")
355+
}
356+
357+
LLVMRemoveEnumAttributeAtIndex(llvm, index.rawValue, attrKind.id)
358+
}
359+
360+
/// Removes a string attribute from the function, its return value or one of
361+
/// its parameters.
362+
///
363+
/// - parameter name: The name of the attribute to remove.
364+
/// - parameter index: The index representing the function, its return value
365+
/// or one of its parameters.
366+
public func removeAttribute(_ name: String, from index: AttributeIndex) {
367+
name.withCString {
368+
LLVMRemoveStringAttributeAtIndex(llvm, index.rawValue, $0, UInt32(name.count))
369+
}
370+
}
371+
372+
/// Gets the attributes of the function, its return value or its parameters.
373+
public func attributes(at index: AttributeIndex) -> [Attribute] {
374+
let attrCount = LLVMGetAttributeCountAtIndex(llvm, index.rawValue)
375+
var attrRefs: [LLVMAttributeRef?] = Array(repeating: nil, count: Int(attrCount))
376+
LLVMGetAttributesAtIndex(llvm, index.rawValue, &attrRefs)
377+
return attrRefs.map { attrRef -> Attribute in
378+
if LLVMIsEnumAttribute(attrRef) != 0 {
379+
return EnumAttribute(llvm: attrRef!)
380+
} else {
381+
return StringAttribute(llvm: attrRef!)
382+
}
383+
}
384+
}
385+
}

0 commit comments

Comments
 (0)