Skip to content

Commit bf20f3a

Browse files
committed
Expand the documentation of Function
1 parent edf00a9 commit bf20f3a

File tree

4 files changed

+112
-12
lines changed

4 files changed

+112
-12
lines changed

Sources/LLVM/Function.swift

Lines changed: 86 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,88 @@
11
#if SWIFT_PACKAGE
22
import cllvm
3+
import llvmshims
34
#endif
45

56
/// A `Function` represents a named function body in LLVM IR source. Functions
67
/// in LLVM IR encapsulate a list of parameters and a sequence of basic blocks
78
/// and provide a way to append to that sequence to build out its body.
9+
///
10+
/// A LLVM function definition contains a list of basic blocks, starting with
11+
/// a privileged first block called the "entry block", and proceeding its
12+
/// terminating instruction to zero or more other basic blocks. The path the
13+
/// flow of control can potentially take, from each block to its terminator
14+
/// and back again, forms the "Control Flow Graph" (CFG) for the function.
15+
///
16+
/// Additional basic blocks may be created and appended to the function at
17+
/// any time.
18+
///
19+
/// let module = Module(name: "Example")
20+
/// let builder = IRBuilder(module: module)
21+
/// let fun = builder.addFunction("example",
22+
/// type: FunctionType(argTypes: [],
23+
/// returnType: VoidType()))
24+
/// // Create and append the entry block
25+
/// let entryBB = fun.appendBasicBlock(named: "entry")
26+
/// // Create and append a standalone basic block
27+
/// let freestanding = BasicBlock(name: "freestanding")
28+
/// fun.append(freestanding)
29+
///
30+
/// A LLVM function always has the type `FunctionType`. This type is used to
31+
/// determine the number and kind of parameters to the function as well as its
32+
/// return value, if any. The parameter values, which would normally enter
33+
/// the entry block, are instead attached to the function and are accessible
34+
/// via the `parameters` property.
35+
///
36+
/// Calling Convention
37+
/// ==================
38+
///
39+
/// By default, all functions in LLVM are invoked with the C calling convention
40+
/// but the exact calling convention of both a function declaration and a
41+
/// `call` instruction are fully configurable.
42+
///
43+
/// let module = Module(name: "Example")
44+
/// let builder = IRBuilder(module: module)
45+
/// let fun = builder.addFunction("example",
46+
/// type: FunctionType(argTypes: [],
47+
/// returnType: VoidType()))
48+
/// // Switch to swiftcc
49+
/// fun.callingConvention = .swift
50+
///
51+
/// The calling convention of a function and a corresponding call instruction
52+
/// must match or the result is undefined.
53+
///
54+
/// Sections
55+
/// ========
56+
///
57+
/// A function may optionally state the section in the object file the function
58+
/// should reside in through the use of a metadata attachment. This can be
59+
/// useful to satisfy target-specific data layout constraints, or to provide
60+
/// some hints to optimizers and linkers. LLVMSwift provides a convenience
61+
/// object called an `MDBuilder` to assist in the creation of this metadata.
62+
///
63+
/// let mdBuilder = MDBuilder()
64+
/// // __attribute__((hot))
65+
/// let hotAttr = mdBuilder.buildFunctionSectionPrefix(".hot")
66+
///
67+
/// let module = Module(name: "Example")
68+
/// let builder = IRBuilder(module: module)
69+
/// let fun = builder.addFunction("example",
70+
/// type: FunctionType(argTypes: [],
71+
/// returnType: VoidType()))
72+
/// // Attach the metadata
73+
/// fun.addMetadata(hotAttr, kind: .sectionPrefix)
74+
///
75+
/// For targets that support it, a function may also specify a COMDAT section.
76+
///
77+
/// fun.comdat = module.comdat(named: "example")
78+
///
79+
/// Debug Information
80+
/// =================
81+
///
82+
/// A function may also carry debug information through special subprogram
83+
/// nodes. These nodes are intended to capture the structure of the function
84+
/// as it appears in the source so that it is available for inspection by a
85+
/// debugger. See `DIBuilderr.buildFunction` for more information.
886
public class Function: IRGlobal {
987
internal let llvm: LLVMValueRef
1088
internal init(llvm: LLVMValueRef) {
@@ -26,17 +104,6 @@ public class Function: IRGlobal {
26104
}
27105

28106
/// Retrieves the entry block of this function.
29-
///
30-
/// The first basic block in a function is special in two ways: it is
31-
/// immediately executed on entrance to the function, and it is not allowed to
32-
/// have predecessor basic blocks (i.e. there can not be any branches to the
33-
/// entry block of a function). Because the block can have no predecessors, it
34-
/// also cannot have any PHI nodes.
35-
///
36-
/// The entry block is also special in that any static allocas emitted into it
37-
/// influence the layout of the stack frame of the function at code generation
38-
/// time. It is therefore often more efficient to emit static allocas in the
39-
/// entry block than anywhere else in the function.
40107
public var entryBlock: BasicBlock? {
41108
guard let blockRef = LLVMGetEntryBasicBlock(llvm) else { return nil }
42109
return BasicBlock(llvm: blockRef)
@@ -78,7 +145,7 @@ public class Function: IRGlobal {
78145

79146
/// Computes the address of the specified basic block in this function.
80147
///
81-
/// Taking the address of the entry block is illegal.
148+
/// - WARNING: Taking the address of the entry block is illegal.
82149
///
83150
/// This value only has defined behavior when used as an operand to the
84151
/// `indirectbr` instruction, or for comparisons against null. Pointer
@@ -170,6 +237,13 @@ public class Function: IRGlobal {
170237
return BasicBlock(llvm: block)
171238
}
172239

240+
/// Appends the named basic block to the body of this function.
241+
///
242+
/// - parameter basicBlock: The block to append.
243+
public func append(_ basicBlock: BasicBlock) {
244+
LLVMAppendExistingBasicBlock(llvm, basicBlock.asLLVM())
245+
}
246+
173247
/// Deletes the function from its containing module.
174248
/// - note: This does not remove calls to this function from the
175249
/// module. Ensure you have removed all instructions that reference

Sources/llvmshims/include/shim.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,7 @@ LLVMMetadataRef LLVMMDNodeInContext2(LLVMContextRef C, LLVMMetadataRef *MDs,
9393

9494
uint64_t LLVMGlobalGetGUID(LLVMValueRef Global);
9595

96+
void LLVMAppendExistingBasicBlock(LLVMValueRef Fn,
97+
LLVMBasicBlockRef BB);
98+
9699
#endif /* LLVMSWIFT_LLVM_SHIM_H */

Sources/llvmshims/src/shim.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@ extern "C" {
116116
// Not to be upstreamed: It's not clear there's value in having this outside
117117
// of PGO passes.
118118
uint64_t LLVMGlobalGetGUID(LLVMValueRef Global);
119+
120+
// https://reviews.llvm.org/D59658
121+
void LLVMAppendExistingBasicBlock(LLVMValueRef Fn,
122+
LLVMBasicBlockRef BB);
119123
}
120124

121125
using namespace llvm;
@@ -345,3 +349,8 @@ LLVMMetadataRef LLVMMDNodeInContext2(LLVMContextRef C, LLVMMetadataRef *MDs,
345349
uint64_t LLVMGlobalGetGUID(LLVMValueRef Glob) {
346350
return unwrap<GlobalValue>(Glob)->getGUID();
347351
}
352+
353+
void LLVMAppendExistingBasicBlock(LLVMValueRef Fn,
354+
LLVMBasicBlockRef BB) {
355+
unwrap<Function>(Fn)->getBasicBlockList().push_back(unwrap(BB));
356+
}

Tests/LLVMTests/ConstantSpec.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,20 @@ import FileCheck
44
import Foundation
55

66
class ConstantSpec : XCTestCase {
7+
func foo() {
8+
let mdBuilder = MDBuilder()
9+
let hotAttr = mdBuilder.buildFunctionSectionPrefix(".hot")
10+
11+
let module = Module(name: "Example")
12+
let builder = IRBuilder(module: module)
13+
let fun = builder.addFunction("example",
14+
type: FunctionType(argTypes: [],
15+
returnType: VoidType()))
16+
fun.appendBasicBlock(named: "entry")
17+
let freestanding = BasicBlock(name: "freestanding")
18+
fun.append(freestanding)
19+
fun.addMetadata(hotAttr, kind: .sectionPrefix)
20+
}
721
func testConstants() {
822
XCTAssert(fileCheckOutput(of: .stderr, withPrefixes: ["SIGNEDCONST"]) {
923
// SIGNEDCONST: ; ModuleID = '[[ModuleName:ConstantTest]]'

0 commit comments

Comments
 (0)