|
1 | 1 | #if SWIFT_PACKAGE
|
2 | 2 | import cllvm
|
| 3 | +import llvmshims |
3 | 4 | #endif
|
4 | 5 |
|
5 | 6 | /// Represents a simple function call.
|
@@ -33,6 +34,22 @@ public struct Call: IRInstruction {
|
33 | 34 | set { LLVMSetTailCall(self.llvm, newValue.llvm) }
|
34 | 35 | }
|
35 | 36 |
|
| 37 | + /// Accesses the tail call marker associated with this call. |
| 38 | + /// |
| 39 | + /// The presence of the tail call marker affects the optimizer's decisions |
| 40 | + /// around tail call optimizations. The presence of a `tail` or `mustTail` |
| 41 | + /// marker, either inserted by the user or by the optimizer, is a strong |
| 42 | + /// hint (or a requirement) that tail call optimizations occur. The presence |
| 43 | + /// of `noTail` acts to block any tail call optimization. |
| 44 | + /// |
| 45 | + /// Tail call optimization is finicky and requires a number of complex |
| 46 | + /// invariants hold before a call is eligible for the optimization. |
| 47 | + /// Even then, it is not necessarily guaranteed by LLVM in all cases. |
| 48 | + public var tailCallKind: TailCallKind { |
| 49 | + get { return TailCallKind(llvm: LLVMGetTailCallKind(self.llvm)) } |
| 50 | + set { return LLVMSetTailCallKind(self.llvm, newValue.llvm) } |
| 51 | + } |
| 52 | + |
36 | 53 | /// Retrieves the alignment of the parameter at the given index.
|
37 | 54 | ///
|
38 | 55 | /// This property is currently set-only due to limitations of the LLVM C API.
|
@@ -66,3 +83,84 @@ public struct Invoke: IRInstruction {
|
66 | 83 | set { LLVMSetUnwindDest(self.llvm, newValue.asLLVM()) }
|
67 | 84 | }
|
68 | 85 | }
|
| 86 | + |
| 87 | +extension Call { |
| 88 | + /// Optimization markers for tail call elimination. |
| 89 | + public enum TailCallKind { |
| 90 | + /// No optimization tail call marker is present. The optimizer is free to |
| 91 | + /// infer one of the other tail call markers. |
| 92 | + case none |
| 93 | + /// Suggests that tail call optimization should be performed on this |
| 94 | + /// function. Note that this is not a guarantee. |
| 95 | + /// |
| 96 | + /// `tail` calls may not access caller-provided allocas, and may not |
| 97 | + /// access varargs. |
| 98 | + /// |
| 99 | + /// Tail call optimization for calls marked tail is guaranteed to occur if |
| 100 | + /// the following conditions are met: |
| 101 | + /// |
| 102 | + /// - Caller and callee both have the calling convention `fastcc`. |
| 103 | + /// - The call is in tail position (ret immediately follows `call` and |
| 104 | + /// `ret` uses value of call or is void). |
| 105 | + /// - Tail call elimination is enabled in the target machine's |
| 106 | + /// `TargetOptions` or is globally enabled in LLVM. |
| 107 | + /// - Platform-specific constraints are met. |
| 108 | + case tail |
| 109 | + /// Requires the tail call optimization be performed in order for this call |
| 110 | + /// to proceed correctly. |
| 111 | + /// |
| 112 | + /// Tail calls guarantee the following invariants: |
| 113 | + /// |
| 114 | + /// - The call will not cause unbounded stack growth if it is part of a |
| 115 | + /// recursive cycle in the call graph. |
| 116 | + /// - Arguments with the `inalloca` attribute are forwarded in place. |
| 117 | + /// - If the musttail call appears in a function with the `thunk` |
| 118 | + /// attribute and the caller and callee both have varargs, than any |
| 119 | + /// unprototyped arguments in register or memory are forwarded to the |
| 120 | + /// callee. Similarly, the return value of the callee is returned the |
| 121 | + /// the caller’s caller, even if a `void` return type is in use. |
| 122 | + /// |
| 123 | + /// `mustTail` calls may not access caller-provided allocas, and may not |
| 124 | + /// access varargs. Unlike `tail`s, they are also subject to the following |
| 125 | + /// restrictions: |
| 126 | + /// |
| 127 | + /// - The call must immediately precede a `ret` instruction, or a pointer |
| 128 | + /// `bitcast` followed by a `ret` instruction. |
| 129 | + /// - The `ret` instruction must return the (possibly `bitcast`ed) value |
| 130 | + /// produced by the `call`, or return `void`. |
| 131 | + /// - The caller and callee prototypes must match. Pointer types of |
| 132 | + /// parameters or return types may differ in pointee type, but not in |
| 133 | + /// address space. |
| 134 | + /// - The calling conventions of the caller and callee must match. |
| 135 | + /// - All ABI-impacting function attributes, such as `sret`, `byval`, |
| 136 | + /// `inreg`, `returned`, and `inalloca`, must match. |
| 137 | + /// - The callee must be varargs iff the caller is varargs. Bitcasting a |
| 138 | + /// non-varargs function to the appropriate varargs type is legal so |
| 139 | + /// long as the non-varargs prefixes obey the other rules. |
| 140 | + case mustTail |
| 141 | + /// Prevents tail call optimizations from being performed or inferred. |
| 142 | + case noTail |
| 143 | + |
| 144 | + internal init(llvm: LLVMTailCallKind) { |
| 145 | + switch llvm { |
| 146 | + case LLVMTailCallKindNone: self = .none |
| 147 | + case LLVMTailCallKindTail: self = .tail |
| 148 | + case LLVMTailCallKindMustTail: self = .mustTail |
| 149 | + case LLVMTailCallKindNoTail: self = .noTail |
| 150 | + default: fatalError("unknown tail call kind \(llvm)") |
| 151 | + } |
| 152 | + } |
| 153 | + |
| 154 | + private static let tailCallKindMapping: [TailCallKind: LLVMTailCallKind] = [ |
| 155 | + .none: LLVMTailCallKindNone, |
| 156 | + .tail: LLVMTailCallKindTail, |
| 157 | + .mustTail: LLVMTailCallKindMustTail, |
| 158 | + .noTail: LLVMTailCallKindNoTail, |
| 159 | + ] |
| 160 | + |
| 161 | + /// Retrieves the corresponding `LLVMTailCallKind`. |
| 162 | + public var llvm: LLVMTailCallKind { |
| 163 | + return TailCallKind.tailCallKindMapping[self]! |
| 164 | + } |
| 165 | + } |
| 166 | +} |
0 commit comments