Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

A Swift wrapper for the LLVM C API (version 11.0)

License

NotificationsYou must be signed in to change notification settings

llvm-swift/LLVMSwift

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Build StatusDocumentationSlack Invite

LLVMSwift is a pure Swift interface to theLLVM API and its associated libraries. It provides native, easy-to-use components to make compiler development fun.

Introduction

LLVM IR

The root unit of organization of an LLVM IR program is aModule

letmodule=Module(name:"main")

LLVM IR construction is handled byIRBuilder objects. AnIRBuilder is a cursor pointed inside a context, and as such has ways of extending that context and moving around inside of it.

Defining a function and moving the cursor to a point where we can begin inserting instructions is done like so:

letbuilder=IRBuilder(module: module)letmain= builder.addFunction("main",                               type:FunctionType([],IntType.int64))letentry= main.appendBasicBlock(named:"entry")builder.positionAtEnd(of: entry)

Inserting instructions creates nativeIRValue placeholder objects that allow us to structure LLVM IR programs just like Swift programs:

letconstant=IntType.int64.constant(21)letsum= builder.buildAdd(constant, constant)builder.buildRet(sum)

This simple program generates the following IR:

//module.dump()definei64@main() {entry:reti6442}

Types

LLVM IR is a strong, statically typed language. As such, values and functionsare tagged with their types, and conversions between them must be explicit (seeConversion Operators).LLVMSwift represents this with values conforming to theIRType protocol and definesthe following types:

TypeRepresents
VoidTypeNothing; Has no size
IntTypeInteger and Boolean values (i1)
FloatTypeFloating-point values
FunctionTypeFunction values
LabelTypeCode labels
TokenTypeValues paired with instructions
MetadataTypeEmbedded metadata
X86MMXTypeX86 MMX values
PointerTypePointer values
VectorTypeSIMD data
ArrayTypeHomogeneous values
Structure TypeHeterogeneous values

Control Flow

Control flow is changed through the unconditional and conditionalbr instruction.

LLVM is also famous for a control-flow specific IR construct called aPHI node. Because all instructions in LLVM IR are in SSA (Single Static Assignment) form, a PHI node is necessary when the value of a variable assignment depends on the path the flow of control takes through the program. For example, let's try to build the following Swift program in IR:

func calculateFibs(_ backward:Bool)->Double{letretVal:Doubleif !backward{    // the fibonacci series (sort of)    retVal=1/89}else{    // the fibonacci series (sort of) backwards    retVal=1/109}return retVal}

Notice that the value ofretVal depends on the path the flow of control takes through this program, so we must emit a PHI node to properly initialize it:

letfunction= builder.addFunction("calculateFibs",                                    type:FunctionType([IntType.int1],FloatType.double))letentryBB= function.appendBasicBlock(named:"entry")builder.positionAtEnd(of: entryBB)// allocate space for a local valueletlocal= builder.buildAlloca(type:FloatType.double, name:"local")// Compare to the conditionlettest= builder.buildICmp(function.parameters[0],IntType.int1.zero(),.equal)// Create basic blocks for "then", "else", and "merge"letthenBB= function.appendBasicBlock(named:"then")letelseBB= function.appendBasicBlock(named:"else")letmergeBB= function.appendBasicBlock(named:"merge")builder.buildCondBr(condition: test, then: thenBB, else: elseBB)// MARK: Then Blockbuilder.positionAtEnd(of: thenBB)// local = 1/89, the fibonacci series (sort of)letthenVal=FloatType.double.constant(1/89)// Branch to the merge blockbuilder.buildBr(mergeBB)// MARK: Else Blockbuilder.positionAtEnd(of: elseBB)// local = 1/109, the fibonacci series (sort of) backwardsletelseVal=FloatType.double.constant(1/109)// Branch to the merge blockbuilder.buildBr(mergeBB)// MARK: Merge Blockbuilder.positionAtEnd(of: mergeBB)letphi= builder.buildPhi(FloatType.double, name:"phi_example")phi.addIncoming([(thenVal, thenBB),(elseVal, elseBB),])builder.buildStore(phi, to: local)letret= builder.buildLoad(local, type:FloatType.double, name:"ret")builder.buildRet(ret)

This program generates the following IR:

definedouble@calculateFibs(i1) {entry:%local =allocadouble%1 =icmpnei1%0,falsebri1%1,label%then,label%elsethen:; preds = %entrybrlabel%mergeelse:; preds = %entrybrlabel%mergemerge:; preds = %else, %then%phi_example =phidouble [0x3F8702E05C0B8170,%then ], [0x3F82C9FB4D812CA0,%else ]storedouble%phi_example,double*%local%ret =loaddouble,double*%localretdouble%ret}

JIT

LLVMSwift provides a JIT abstraction to make executing code in LLVM modules quick and easy. Let's execute the PHI node example from before:

// Setup the JITletjit=tryJIT(machine:TargetMachine())typealiasFnPtr=@convention(c)(Bool)->Double_=try jit.addEagerlyCompiledIR(module){(name)->JIT.TargetAddressinreturnJIT.TargetAddress()}// Retrieve a handle to the function we're going to invokeletaddr=try jit.address(of:"calculateFibs")letfn=unsafeBitCast(addr, to:FnPtr.self)// Call the function!print(fn(true)) // 0.00917431192660551...print(fn(false)) // 0.0112359550561798...

Installation

There are a couple annoying steps you need to accomplish before buildingLLVMSwift:

  • Install LLVM 11.0+ using your favorite package manager. For example:
    • brew install llvm@11
  • Ensurellvm-config is in yourPATH
    • That will reside in the/bin folder wherever your package managerinstalled LLVM.
  • Create a pkg-config file for your specific LLVM installation.
    • We have a utility for this:swift utils/make-pkgconfig.swift

Once you do that, you can add LLVMSwift as a dependency for your own Swiftcompiler projects!

Installation with Swift Package Manager

.package(url:"https://github.com/llvm-swift/LLVMSwift.git", from:"0.8.0")

Installation without Swift Package Manager

We really recommend using SwiftPM with LLVMSwift, but if your project isstructured in such a way that makes using SwiftPM impractical or impossible,use the following instructions:

  • Xcode:
    • Add this repository as a git submodule
    • Add the files inSources/ to your Xcode project.
    • UnderLibrary Search Paths add the output ofllvm-config --libdir
    • UnderHeader Search Paths add the output ofllvm-config --includedir
    • UnderLink Target with Libraries drag in/path/to/your/llvm/lib/libLLVM.dylib

This project is used byTrill forall its code generation.

Authors

License

This project is released under the MIT license, a copy of which is availablein this repo.

About

A Swift wrapper for the LLVM C API (version 11.0)

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors17

Languages


[8]ページ先頭

©2009-2025 Movatter.jp