Slide 1

Slide 1 text

)PXUP$MBOH:PVS%SBHPO #VJMEJOHB$PNQJMFSXJUI--7. )BSMBO)BTLJOT]!IBSMBOIBTLJOT

Slide 2

Slide 2 text

8IBUTUIF1MBO

Slide 3

Slide 3 text

,BMFJEPTDPQF def fact(n) if n = 0 then 1 else n * fact(n - 1);

Slide 4

Slide 4 text

"HFOEB  (PPWFSDPNQJMFSCBTJDT  #VJMEBMFYFS  #VJMEBQBSTFS  (FOFSBUF--7.*3

Slide 5

Slide 5 text

$PNQJMFST

Slide 6

Slide 6 text

$PNQJMFST Input

Slide 7

Slide 7 text

$PNQJMFST -FYFS Input

Slide 8

Slide 8 text

$PNQJMFST -FYFS Token Stream Input

Slide 9

Slide 9 text

$PNQJMFST -FYFS Token Stream Input 1BSTFS

Slide 10

Slide 10 text

$PNQJMFST -FYFS Token Stream Input 1BSTFS AST

Slide 11

Slide 11 text

$PNQJMFST -FYFS Token Stream AST Input 1BSTFS $PEF(FO

Slide 12

Slide 12 text

8IBUJT--7.  "TFUPGMJCSBSJFTGPSDPNQJMFST  $FOUFSFEBSPVOE--7.*OUFSNFEJBUF3FQSFTFOUBUJPO  $PEFHFOFSBUJPOGPSUPOTPGUBSHFUT

Slide 13

Slide 13 text

4UFQ0OF -FYFS Token Stream AST Input 1BSTFS $PEF(FO

Slide 14

Slide 14 text

4UFQ0OF -FYFS Token Stream AST Input 1BSTFS $PEF(FO

Slide 15

Slide 15 text

4USVDUVSF  3FDFJWFTJOQVUBTBTUSJOH  8BMLTUISPVHIUIFTUSJOH MPPLJOHGPSQBUUFSOT  1BUUFSOTBSFDBMMFEUPLFOT  ,FFQFBUJOHDIBSBDUFST NBLJOHUPLFOT VOUJM ZPVIJUUIFFOE

Slide 16

Slide 16 text

def fact(n) if n = 0 then 1 else n * fact(n - 1); [ ] .def, .ident("fact"), .semicolon .ident("n"), .if, .ident("n"), .oper(=), .num(0), .then, .num(1), .else, .oper(*), .ident("fact"), .lParen, .ident("n"), .oper(-), .num(1), .rParen, .lParen, .rParen, .ident("n"),

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

enum Token { }

Slide 19

Slide 19 text

enum Token { } case leftParen, rightParen, def, extern, comma, semicolon, `if`, then, `else`

Slide 20

Slide 20 text

enum Token { } case leftParen, rightParen, def, extern, comma, semicolon, `if`, then, `else` case identifier(String) case number(Double)

Slide 21

Slide 21 text

enum Token { } case leftParen, rightParen, def, extern, comma, semicolon, `if`, then, `else` case identifier(String) case number(Double) case `operator`(BinaryOperator) enum BinaryOperator: Character { case plus = "+", minus = "-", times = "*", divide = "/", mod = "%", equals = "=" }

Slide 22

Slide 22 text

No content

Slide 23

Slide 23 text

class Lexer {

Slide 24

Slide 24 text

class Lexer { let input: String var index: String.Index

Slide 25

Slide 25 text

class Lexer { init(input: String) { self.input = input self.index = input.startIndex } var currentChar: Character? { return index < input.endIndex ? input[index] : nil } func advanceIndex() { input.characters.formIndex(after: &index) } let input: String var index: String.Index

Slide 26

Slide 26 text

func advanceToNextToken() -> Token? {

Slide 27

Slide 27 text

func advanceToNextToken() -> Token? { while let char = currentChar, char.isSpace { advanceIndex() }

Slide 28

Slide 28 text

func advanceToNextToken() -> Token? { while let char = currentChar, char.isSpace { advanceIndex() } guard let char = currentChar else { return nil }

Slide 29

Slide 29 text

func advanceToNextToken() -> Token? { while let char = currentChar, char.isSpace { advanceIndex() } guard let char = currentChar else { return nil } let singleTokMapping: [Character: Token] = [ ",": .comma, "(": .leftParen, ")": .rightParen, ";": .semicolon, "+": .operator(.plus), "-": .operator(.minus), "*": .operator(.times), "/": .operator(.divide), "%": .operator(.mod), "=": .operator(.equals) ]

Slide 30

Slide 30 text

func advanceToNextToken() -> Token? { while let char = currentChar, char.isSpace { advanceIndex() } guard let char = currentChar else { return nil } if let tok = singleTokMapping[char] { advanceIndex() return tok } let singleTokMapping: [Character: Token] = [ ",": .comma, "(": .leftParen, ")": .rightParen, ";": .semicolon, "+": .operator(.plus), "-": .operator(.minus), "*": .operator(.times), "/": .operator(.divide), "%": .operator(.mod), "=": .operator(.equals) ]

Slide 31

Slide 31 text

if char.isAlphanumeric {

Slide 32

Slide 32 text

if char.isAlphanumeric { let str = readIdentifierOrNumber()

Slide 33

Slide 33 text

if char.isAlphanumeric { let str = readIdentifierOrNumber() if let dblVal = Double(str) { return .number(dblVal) }

Slide 34

Slide 34 text

if char.isAlphanumeric { let str = readIdentifierOrNumber() if let dblVal = Double(str) { return .number(dblVal) } switch str { case "def": return .def case "extern": return .extern case "if": return .if case "then": return .then case "else": return .else default: return .identifier(str) }

Slide 35

Slide 35 text

if char.isAlphanumeric { let str = readIdentifierOrNumber() if let dblVal = Double(str) { return .number(dblVal) } switch str { case "def": return .def case "extern": return .extern case "if": return .if case "then": return .then case "else": return .else default: return .identifier(str) } } return nil }

Slide 36

Slide 36 text

func lex() -> [Token] { var toks = [Token]() while let tok = advanceToNextToken() { toks.append(tok) } return toks } }

Slide 37

Slide 37 text

-FYFS✅

Slide 38

Slide 38 text

4UFQ5XP -FYFS Token Stream AST Input 1BSTFS $PEF(FO

Slide 39

Slide 39 text

4UFQ5XP -FYFS Token Stream AST Input 1BSTFS $PEF(FO

Slide 40

Slide 40 text

"CTUSBDU4ZOUBY5SFF 'JMF

Slide 41

Slide 41 text

"CTUSBDU4ZOUBY5SFF &YUFSO 'JMF

Slide 42

Slide 42 text

"CTUSBDU4ZOUBY5SFF &YUFSO 'VODUJPO 'JMF

Slide 43

Slide 43 text

"CTUSBDU4ZOUBY5SFF &YUFSO 'VODUJPO &YQSFTTJPO 'JMF

Slide 44

Slide 44 text

,BMFJEPTDPQF"45 extern sin(n); &YUFSOBM%FGJOJUJPOT struct Prototype { let name: String let params: [String] } 4XJGU4USVDUVSF

Slide 45

Slide 45 text

extern sin(n); &YUFSOBM%FGJOJUJPOT def plusOne(n) n + 1; 'VODUJPO%FGJOJUJPOT struct Prototype { let name: String let params: [String] } struct Definition { let prototype: Prototype let expr: Expr } 4XJGU4USVDUVSF ,BMFJEPTDPQF"45

Slide 46

Slide 46 text

extern sin(n); &YUFSOBM%FGJOJUJPOT def plusOne(n) n + 1; 'VODUJPO%FGJOJUJPOT n + 1 * foo(n * 3); &YQSFTTJPOT struct Prototype { let name: String let params: [String] } 4XJGU4USVDUVSF struct Definition { let prototype: Prototype let expr: Expr } indirect enum Expr { case number(Double) case variable(String) case binary(Expr, BinaryOperator, Expr) case call(String, [Expr]) case ifelse(Expr, Expr, Expr) } ,BMFJEPTDPQF"45

Slide 47

Slide 47 text

4USVDUVSF  3FDFJWFTUPLFOTGSPN-FYFS  3FDVSTJWF%FTDFOU  1BSTFSTSFDVSTFJOUPFBDIPUIFS  FH%FGJOJUJPOVTFT1SPUPUZQFBOE&YQSFTTJPO  $POTUBOUMZVQEBUFUIF"CTUSBDU4ZOUBY5SFF

Slide 48

Slide 48 text

var externs = [Prototype]() var definitions = [Definition]() var expressions = [Expr]() class File {

Slide 49

Slide 49 text

var externs = [Prototype]() var definitions = [Definition]() var expressions = [Expr]() var prototypeMap = [String: Prototype]() class File { func prototype(name: String) -> Prototype? { return prototypeMap[name] }

Slide 50

Slide 50 text

var externs = [Prototype]() var definitions = [Definition]() var expressions = [Expr]() var prototypeMap = [String: Prototype]() func addExtern(_ prototype: Prototype) { externs.append(prototype) prototypeMap[prototype.name] = prototype } func addDefinition(_ definition: Definition) { definitions.append(definition) prototypeMap[definition.prototype.name] = definition.prototype } class File { func prototype(name: String) -> Prototype? { return prototypeMap[name] }

Slide 51

Slide 51 text

var externs = [Prototype]() var definitions = [Definition]() var expressions = [Expr]() var prototypeMap = [String: Prototype]() class File { func addExpression(_ expression: Expr) { expressions.append(expression) } func addExtern(_ prototype: Prototype) { externs.append(prototype) prototypeMap[prototype.name] = prototype } func addDefinition(_ definition: Definition) { definitions.append(definition) prototypeMap[definition.prototype.name] = definition.prototype } func prototype(name: String) -> Prototype? { return prototypeMap[name] } }

Slide 52

Slide 52 text

enum ParseError: Error { case unexpectedToken(Token) case unexpectedEOF } class Parser {

Slide 53

Slide 53 text

class Parser { enum ParseError: Error { case unexpectedToken(Token) case unexpectedEOF } let tokens: [Token] var index = 0 init(tokens: [Token]) { self.tokens = tokens } var currentToken: Token? { return index < tokens.count ? tokens[index] : nil } func consumeToken() { index += 1 }

Slide 54

Slide 54 text

func consume(_ token: Token) throws { guard let tok = currentToken else { throw ParseError.unexpectedEOF } guard token == tok else { throw ParseError.unexpectedToken(token) } consumeToken() }

Slide 55

Slide 55 text

func consume(_ token: Token) throws { guard let tok = currentToken else { throw ParseError.unexpectedEOF } guard token == tok else { throw ParseError.unexpectedToken(token) } consumeToken() } func parsePrototype() throws -> Prototype { let name = try parseIdentifier() let params = try parseCommaSeparatedInParens(parseIdentifier) return Prototype(name: name, params: params) }

Slide 56

Slide 56 text

func consume(_ token: Token) throws { guard let tok = currentToken else { throw ParseError.unexpectedEOF } guard token == tok else { throw ParseError.unexpectedToken(token) } consumeToken() } func parsePrototype() throws -> Prototype { let name = try parseIdentifier() let params = try parseCommaSeparatedInParens(parseIdentifier) return Prototype(name: name, params: params) } func parseExtern() throws -> Prototype { try consume(.extern) let prototype = try parsePrototype() try consume(.semicolon) return prototype }

Slide 57

Slide 57 text

func parseExpr() throws -> Expr {

Slide 58

Slide 58 text

func parseExpr() throws -> Expr { guard let token = currentToken else { throw ParseError.unexpectedEOF }

Slide 59

Slide 59 text

func parseExpr() throws -> Expr { guard let token = currentToken else { throw ParseError.unexpectedEOF } var expr: Expr switch token {

Slide 60

Slide 60 text

func parseExpr() throws -> Expr { guard let token = currentToken else { throw ParseError.unexpectedEOF } var expr: Expr case .number(let value): consumeToken() expr = .number(value) switch token {

Slide 61

Slide 61 text

func parseExpr() throws -> Expr { guard let token = currentToken else { throw ParseError.unexpectedEOF } var expr: Expr case .leftParen: // ( ) consumeToken() expr = try parseExpr() try consume(.rightParen) case .number(let value): consumeToken() expr = .number(value) switch token {

Slide 62

Slide 62 text

func parseExpr() throws -> Expr { guard let token = currentToken else { throw ParseError.unexpectedEOF } var expr: Expr case .leftParen: // ( ) consumeToken() expr = try parseExpr() try consume(.rightParen) case .number(let value): consumeToken() expr = .number(value) case .identifier(let value): consumeToken() if case .leftParen? = currentToken { let params = try parseCommaSeparatedInParens(parseExpr) expr = .call(value, params) } else { expr = .variable(value) } switch token {

Slide 63

Slide 63 text

case .identifier(let value): consumeToken() if case .leftParen? = currentToken { let params = try parseCommaSeparatedInParens(parseExpr) expr = .call(value, params) } else { expr = .variable(value) } case .if: // if then else consumeToken() let cond = try parseExpr() try consume(.then) let thenVal = try parseExpr() try consume(.else) let elseVal = try parseExpr() expr = .ifelse(cond, thenVal, elseVal)

Slide 64

Slide 64 text

case .identifier(let value): consumeToken() if case .leftParen? = currentToken { let params = try parseCommaSeparatedInParens(parseExpr) expr = .call(value, params) } else { expr = .variable(value) } case .if: // if then else consumeToken() let cond = try parseExpr() try consume(.then) let thenVal = try parseExpr() try consume(.else) let elseVal = try parseExpr() expr = .ifelse(cond, thenVal, elseVal) default: throw ParseError.unexpectedToken(token) }

Slide 65

Slide 65 text

case .if: // if then else consumeToken() let cond = try parseExpr() try consume(.then) let thenVal = try parseExpr() try consume(.else) let elseVal = try parseExpr() expr = .ifelse(cond, thenVal, elseVal) default: throw ParseError.unexpectedToken(token) } if case .operator(let op)? = currentToken { consumeToken() let rhs = try parseExpr() return .binary(expr, op, rhs) } return expr }

Slide 66

Slide 66 text

func parseDefinition() throws -> Definition { try consume(.def) let prototype = try parsePrototype() let expr = try parseExpr() try consume(.semicolon) return Definition(prototype: prototype, expr: expr) }

Slide 67

Slide 67 text

func parseFile() throws -> File { let file = File() while let tok = currentToken { switch tok { case .extern: file.addExtern(try parseExtern()) case .def: file.addDefinition(try parseDefinition()) default: let expr = try parseExpr() try consume(.semicolon) file.addExpression(expr) } } return file }

Slide 68

Slide 68 text

No content

Slide 69

Slide 69 text

4UFQ5ISFF -FYFS Token Stream AST Input 1BSTFS $PEF(FO

Slide 70

Slide 70 text

4UFQ5ISFF -FYFS Token Stream AST Input 1BSTFS $PEF(FO

Slide 71

Slide 71 text

--7.*3  )JHIMFWFM"TTFNCMZ  /PMPPQT POMZHPUPT  &YQMJDJUUZQFTFWFSZXIFSF  %POUUIJOLBCPVUCJUT  4UBUJD4JOHMF"TTJHONFOU define double @plusOne(double %n) { entry: %0 = fadd double %n, 1.000000e+00 ret double %0 } def plusOne(n) n + 1;

Slide 72

Slide 72 text

4UBUJD4JOHMF"TTJHONFOU define double @plusOne(double %n) { entry: %0 = fadd double %n, 1.000000e+00

Slide 73

Slide 73 text

4UBUJD4JOHMF"TTJHONFOU define double @plusOne(double %n) { entry: %0 = fadd double %n, 1.000000e+00 %1 = fmul double %0, 2.000000e+00

Slide 74

Slide 74 text

4UBUJD4JOHMF"TTJHONFOU define double @plusOne(double %n) { entry: %0 = fadd double %n, 1.000000e+00 %1 = fmul double %0, 2.000000e+00 %2 = fdiv double %1, 3.141592e+00

Slide 75

Slide 75 text

4UBUJD4JOHMF"TTJHONFOU define double @plusOne(double %n) { entry: %0 = fadd double %n, 1.000000e+00 %1 = fmul double %0, 2.000000e+00 %2 = fdiv double %1, 3.141592e+00 ret double %2 }

Slide 76

Slide 76 text

)PXEPXFVTF--7.JO4XJGU

Slide 77

Slide 77 text

--7.JTB$ -JCSBSZ 4XJGUBOE$ BSFOUPOTQFBLJOHUFSNT

Slide 78

Slide 78 text

--7.$"1* 6OTBGF.VUBCMF1PJOUFS--7.7BMVF3FG withUnsafeMutableBufferPointer() LLVMAppendBasicBlockInContext(_:UnsafeMutablePointer _:LLVMContextRef!)

Slide 79

Slide 79 text

0QFO4PVSDF

Slide 80

Slide 80 text

class IRGenerator { let module: Module let builder: IRBuilder let file: File

Slide 81

Slide 81 text

class IRGenerator { private var parameterValues = [String: IRValue]() let module: Module let builder: IRBuilder let file: File

Slide 82

Slide 82 text

class IRGenerator { private var parameterValues = [String: IRValue]() init(file: File) { self.module = Module(name: "kaleidoscope") self.builder = IRBuilder(module: module) self.file = file } let module: Module let builder: IRBuilder let file: File

Slide 83

Slide 83 text

@discardableResult func emitPrototype(_ prototype: Prototype) -> Function { if let function = module.function(named: prototype.name) { return function }

Slide 84

Slide 84 text

@discardableResult func emitPrototype(_ prototype: Prototype) -> Function { if let function = module.function(named: prototype.name) { return function } let argTypes = [IRType](repeating: FloatType.double, count: prototype.params.count)

Slide 85

Slide 85 text

@discardableResult func emitPrototype(_ prototype: Prototype) -> Function { if let function = module.function(named: prototype.name) { return function } let argTypes = [IRType](repeating: FloatType.double, count: prototype.params.count) let funcType = FunctionType(argTypes: argTypes, returnType: FloatType.double)

Slide 86

Slide 86 text

@discardableResult func emitPrototype(_ prototype: Prototype) -> Function { if let function = module.function(named: prototype.name) { return function } let argTypes = [IRType](repeating: FloatType.double, count: prototype.params.count) let funcType = FunctionType(argTypes: argTypes, returnType: FloatType.double) let function = builder.addFunction(prototype.name, type: funcType)

Slide 87

Slide 87 text

@discardableResult func emitPrototype(_ prototype: Prototype) -> Function { if let function = module.function(named: prototype.name) { return function } let argTypes = [IRType](repeating: FloatType.double, count: prototype.params.count) let funcType = FunctionType(argTypes: argTypes, returnType: FloatType.double) let function = builder.addFunction(prototype.name, type: funcType) for (var param, name) in zip(function.parameters, prototype.params) { param.name = name }

Slide 88

Slide 88 text

@discardableResult func emitPrototype(_ prototype: Prototype) -> Function { if let function = module.function(named: prototype.name) { return function } let argTypes = [IRType](repeating: FloatType.double, count: prototype.params.count) let funcType = FunctionType(argTypes: argTypes, returnType: FloatType.double) let function = builder.addFunction(prototype.name, type: funcType) for (var param, name) in zip(function.parameters, prototype.params) { param.name = name } return function }

Slide 89

Slide 89 text

@discardableResult func emitPrototype(_ prototype: Prototype) -> Function { if let function = module.function(named: prototype.name) { return function } let argTypes = [IRType](repeating: FloatType.double, count: prototype.params.count) let funcType = FunctionType(argTypes: argTypes, returnType: FloatType.double) let function = builder.addFunction(prototype.name, type: funcType) for (var param, name) in zip(function.parameters, prototype.params) { param.name = name } return function } // declare double @foo(double %n, double %m)

Slide 90

Slide 90 text

@discardableResult func emitDefinition(_ definition: Definition) throws -> Function { let function = emitPrototype(definition.prototype)

Slide 91

Slide 91 text

@discardableResult func emitDefinition(_ definition: Definition) throws -> Function { let function = emitPrototype(definition.prototype) for (idx, arg) in definition.prototype.params.enumerated() { let param = function.parameter(at: idx)! parameterValues[arg] = param }

Slide 92

Slide 92 text

@discardableResult func emitDefinition(_ definition: Definition) throws -> Function { let function = emitPrototype(definition.prototype) for (idx, arg) in definition.prototype.params.enumerated() { let param = function.parameter(at: idx)! parameterValues[arg] = param } let entryBlock = function.appendBasicBlock(named: "entry") builder.positionAtEnd(of: entryBlock)

Slide 93

Slide 93 text

#BTJD#MPDLT define double @plusOne(double %n) { entry: %r = fadd double %n, 1.000000e+00 br %next next: %g = fmul double %r, 1.100000e+00 ret double %g }

Slide 94

Slide 94 text

@discardableResult func emitDefinition(_ definition: Definition) throws -> Function { let function = emitPrototype(definition.prototype) for (idx, arg) in definition.prototype.params.enumerated() { let param = function.parameter(at: idx)! parameterValues[arg] = param } let entryBlock = function.appendBasicBlock(named: "entry") builder.positionAtEnd(of: entryBlock)

Slide 95

Slide 95 text

@discardableResult func emitDefinition(_ definition: Definition) throws -> Function { let function = emitPrototype(definition.prototype) for (idx, arg) in definition.prototype.params.enumerated() { let param = function.parameter(at: idx)! parameterValues[arg] = param } let entryBlock = function.appendBasicBlock(named: "entry") builder.positionAtEnd(of: entryBlock) let expr = try emitExpr(definition.expr) builder.buildRet(expr)

Slide 96

Slide 96 text

@discardableResult func emitDefinition(_ definition: Definition) throws -> Function { let function = emitPrototype(definition.prototype) for (idx, arg) in definition.prototype.params.enumerated() { let param = function.parameter(at: idx)! parameterValues[arg] = param } let entryBlock = function.appendBasicBlock(named: "entry") builder.positionAtEnd(of: entryBlock) let expr = try emitExpr(definition.expr) builder.buildRet(expr) parameterValues.removeAll() return function }

Slide 97

Slide 97 text

func emitExpr(_ expr: Expr) throws -> IRValue { switch expr {

Slide 98

Slide 98 text

func emitExpr(_ expr: Expr) throws -> IRValue { switch expr { case .number(let value): return FloatType.double.constant(value)

Slide 99

Slide 99 text

func emitExpr(_ expr: Expr) throws -> IRValue { switch expr { case .number(let value): return FloatType.double.constant(value) case .variable(let name): guard let param = parameterValues[name] else { throw IRError.unknownVariable(name) } return param

Slide 100

Slide 100 text

func emitExpr(_ expr: Expr) throws -> IRValue { switch expr { case .number(let value): return FloatType.double.constant(value) case .variable(let name): guard let param = parameterValues[name] else { throw IRError.unknownVariable(name) } return param case .call(let name, let args): guard let prototype = file.prototype(name: name) else { throw IRError.unknownFunction(name) }

Slide 101

Slide 101 text

func emitExpr(_ expr: Expr) throws -> IRValue { switch expr { case .number(let value): return FloatType.double.constant(value) case .variable(let name): guard let param = parameterValues[name] else { throw IRError.unknownVariable(name) } return param guard prototype.params.count == args.count else { throw IRError.wrongNumberOfArgs(name, expected: prototype.params.count, got: args.count) } case .call(let name, let args): guard let prototype = file.prototype(name: name) else { throw IRError.unknownFunction(name) }

Slide 102

Slide 102 text

func emitExpr(_ expr: Expr) throws -> IRValue { switch expr { case .number(let value): return FloatType.double.constant(value) case .variable(let name): guard let param = parameterValues[name] else { throw IRError.unknownVariable(name) } return param guard prototype.params.count == args.count else { throw IRError.wrongNumberOfArgs(name, expected: prototype.params.count, got: args.count) } let callArgs = try args.map(emitExpr) case .call(let name, let args): guard let prototype = file.prototype(name: name) else { throw IRError.unknownFunction(name) }

Slide 103

Slide 103 text

func emitExpr(_ expr: Expr) throws -> IRValue { switch expr { case .number(let value): return FloatType.double.constant(value) case .variable(let name): guard let param = parameterValues[name] else { throw IRError.unknownVariable(name) } return param guard prototype.params.count == args.count else { throw IRError.wrongNumberOfArgs(name, expected: prototype.params.count, got: args.count) } let callArgs = try args.map(emitExpr) let function = emitPrototype(prototype) case .call(let name, let args): guard let prototype = file.prototype(name: name) else { throw IRError.unknownFunction(name) } return builder.buildCall(function, args: callArgs)

Slide 104

Slide 104 text

case .binary(let lhs, let op, let rhs):

Slide 105

Slide 105 text

case .binary(let lhs, let op, let rhs): let lhsVal = try emitExpr(lhs) let rhsVal = try emitExpr(rhs)

Slide 106

Slide 106 text

case .binary(let lhs, let op, let rhs): let lhsVal = try emitExpr(lhs) let rhsVal = try emitExpr(rhs) switch op {

Slide 107

Slide 107 text

case .binary(let lhs, let op, let rhs): let lhsVal = try emitExpr(lhs) let rhsVal = try emitExpr(rhs) switch op { case .plus: return builder.buildAdd(lhsVal, rhsVal)

Slide 108

Slide 108 text

case .binary(let lhs, let op, let rhs): let lhsVal = try emitExpr(lhs) let rhsVal = try emitExpr(rhs) switch op { case .plus: return builder.buildAdd(lhsVal, rhsVal) case .minus: return builder.buildSub(lhsVal, rhsVal) case .divide: return builder.buildDiv(lhsVal, rhsVal) case .times: return builder.buildMul(lhsVal, rhsVal) case .mod: return builder.buildRem(lhsVal, rhsVal)

Slide 109

Slide 109 text

case .binary(let lhs, let op, let rhs): let lhsVal = try emitExpr(lhs) let rhsVal = try emitExpr(rhs) switch op { case .plus: return builder.buildAdd(lhsVal, rhsVal) case .minus: return builder.buildSub(lhsVal, rhsVal) case .divide: return builder.buildDiv(lhsVal, rhsVal) case .times: return builder.buildMul(lhsVal, rhsVal) case .mod: return builder.buildRem(lhsVal, rhsVal) case .equals:

Slide 110

Slide 110 text

case .binary(let lhs, let op, let rhs): let lhsVal = try emitExpr(lhs) let rhsVal = try emitExpr(rhs) switch op { case .plus: return builder.buildAdd(lhsVal, rhsVal) case .minus: return builder.buildSub(lhsVal, rhsVal) case .divide: return builder.buildDiv(lhsVal, rhsVal) case .times: return builder.buildMul(lhsVal, rhsVal) case .mod: return builder.buildRem(lhsVal, rhsVal) case .equals: let comparison = builder.buildFCmp(lhsVal, rhsVal, .orderedEqual)

Slide 111

Slide 111 text

case .binary(let lhs, let op, let rhs): let lhsVal = try emitExpr(lhs) let rhsVal = try emitExpr(rhs) switch op { case .plus: return builder.buildAdd(lhsVal, rhsVal) case .minus: return builder.buildSub(lhsVal, rhsVal) case .divide: return builder.buildDiv(lhsVal, rhsVal) case .times: return builder.buildMul(lhsVal, rhsVal) case .mod: return builder.buildRem(lhsVal, rhsVal) case .equals: return builder.buildIntToFP(comparison, type: FloatType.double, signed: false) } let comparison = builder.buildFCmp(lhsVal, rhsVal, .orderedEqual)

Slide 112

Slide 112 text

case .ifelse(let cond, let thenExpr, let elseExpr):

Slide 113

Slide 113 text

*G4UBUFNFOUT def simpleIf(n) if n then n + 1 else 0

Slide 114

Slide 114 text

*G4UBUFNFOUT define double @simpleIf(double %n) { entry: %cmp = fcmp one double %n, 0.000000e+00 def simpleIf(n) if n then n + 1 else 0

Slide 115

Slide 115 text

*G4UBUFNFOUT define double @simpleIf(double %n) { entry: %cmp = fcmp one double %n, 0.000000e+00 br i1 %cmp, label %then, label %else def simpleIf(n) if n then n + 1 else 0

Slide 116

Slide 116 text

*G4UBUFNFOUT define double @simpleIf(double %n) { entry: %cmp = fcmp one double %n, 0.000000e+00 br i1 %cmp, label %then, label %else then: %1 = fadd double %n, 1.000000e+00 br label %merge def simpleIf(n) if n then n + 1 else 0

Slide 117

Slide 117 text

*G4UBUFNFOUT define double @simpleIf(double %n) { entry: %cmp = fcmp one double %n, 0.000000e+00 br i1 %cmp, label %then, label %else then: %1 = fadd double %n, 1.000000e+00 br label %merge else: br label %merge def simpleIf(n) if n then n + 1 else 0

Slide 118

Slide 118 text

*G4UBUFNFOUT define double @simpleIf(double %n) { entry: %cmp = fcmp one double %n, 0.000000e+00 br i1 %cmp, label %then, label %else then: %1 = fadd double %n, 1.000000e+00 br label %merge else: br label %merge merge: %2 = phi double ret double %2 } def simpleIf(n) if n then n + 1 else 0 [ %1, %then ], [ 0.000000e+00, %else ]

Slide 119

Slide 119 text

*G4UBUFNFOUT define double @simpleIf(double %n) { entry: %cmp = fcmp one double %n, 0.000000e+00 br i1 %cmp, label %then, label %else then: %1 = fadd double %n, 1.000000e+00 br label %merge else: br label %merge merge: %2 = phi double ret double %2 } def simpleIf(n) if n then n + 1 else 0 [ %1, %then ], [ 0.000000e+00, %else ]

Slide 120

Slide 120 text

*G4UBUFNFOUT define double @simpleIf(double %n) { entry: %cmp = fcmp one double %n, 0.000000e+00 br i1 %cmp, label %then, label %else then: %1 = fadd double %n, 1.000000e+00 br label %merge else: br label %merge merge: %2 = phi double ret double %2 } def simpleIf(n) if n then n + 1 else 0 [ %1, %then ], [ 0.000000e+00, %else ]

Slide 121

Slide 121 text

case .ifelse(let cond, let thenExpr, let elseExpr): let checkCond = builder.buildFCmp(try emitExpr(cond), FloatType.double.constant(0.0), .orderedNotEqual)

Slide 122

Slide 122 text

case .ifelse(let cond, let thenExpr, let elseExpr): let checkCond = builder.buildFCmp(try emitExpr(cond), FloatType.double.constant(0.0), .orderedNotEqual) let thenBB = builder.currentFunction!.appendBasicBlock(named: "then") let elseBB = builder.currentFunction!.appendBasicBlock(named: "else") let mergeBB = builder.currentFunction!.appendBasicBlock(named: "merge")

Slide 123

Slide 123 text

case .ifelse(let cond, let thenExpr, let elseExpr): let checkCond = builder.buildFCmp(try emitExpr(cond), FloatType.double.constant(0.0), .orderedNotEqual) let thenBB = builder.currentFunction!.appendBasicBlock(named: "then") let elseBB = builder.currentFunction!.appendBasicBlock(named: "else") let mergeBB = builder.currentFunction!.appendBasicBlock(named: "merge") builder.buildCondBr(condition: checkCond, then: thenBB, else: elseBB)

Slide 124

Slide 124 text

case .ifelse(let cond, let thenExpr, let elseExpr): let checkCond = builder.buildFCmp(try emitExpr(cond), FloatType.double.constant(0.0), .orderedNotEqual) let thenBB = builder.currentFunction!.appendBasicBlock(named: "then") let elseBB = builder.currentFunction!.appendBasicBlock(named: "else") let mergeBB = builder.currentFunction!.appendBasicBlock(named: "merge") builder.buildCondBr(condition: checkCond, then: thenBB, else: elseBB) builder.positionAtEnd(of: thenBB) let thenVal = try emitExpr(thenExpr) builder.buildBr(mergeBB)

Slide 125

Slide 125 text

case .ifelse(let cond, let thenExpr, let elseExpr): let checkCond = builder.buildFCmp(try emitExpr(cond), FloatType.double.constant(0.0), .orderedNotEqual) let thenBB = builder.currentFunction!.appendBasicBlock(named: "then") let elseBB = builder.currentFunction!.appendBasicBlock(named: "else") let mergeBB = builder.currentFunction!.appendBasicBlock(named: "merge") builder.buildCondBr(condition: checkCond, then: thenBB, else: elseBB) builder.positionAtEnd(of: thenBB) let thenVal = try emitExpr(thenExpr) builder.buildBr(mergeBB) builder.positionAtEnd(of: elseBB) let elseVal = try emitExpr(elseExpr) builder.buildBr(mergeBB)

Slide 126

Slide 126 text

case .ifelse(let cond, let thenExpr, let elseExpr): let checkCond = builder.buildFCmp(try emitExpr(cond), FloatType.double.constant(0.0), .orderedNotEqual) let thenBB = builder.currentFunction!.appendBasicBlock(named: "then") let elseBB = builder.currentFunction!.appendBasicBlock(named: "else") let mergeBB = builder.currentFunction!.appendBasicBlock(named: "merge") builder.buildCondBr(condition: checkCond, then: thenBB, else: elseBB) builder.positionAtEnd(of: thenBB) let thenVal = try emitExpr(thenExpr) builder.buildBr(mergeBB) builder.positionAtEnd(of: elseBB) let elseVal = try emitExpr(elseExpr) builder.buildBr(mergeBB) builder.positionAtEnd(of: mergeBB)

Slide 127

Slide 127 text

case .ifelse(let cond, let thenExpr, let elseExpr): let checkCond = builder.buildFCmp(try emitExpr(cond), FloatType.double.constant(0.0), .orderedNotEqual) let thenBB = builder.currentFunction!.appendBasicBlock(named: "then") let elseBB = builder.currentFunction!.appendBasicBlock(named: "else") let mergeBB = builder.currentFunction!.appendBasicBlock(named: "merge") builder.buildCondBr(condition: checkCond, then: thenBB, else: elseBB) builder.positionAtEnd(of: thenBB) let thenVal = try emitExpr(thenExpr) builder.buildBr(mergeBB) builder.positionAtEnd(of: elseBB) let elseVal = try emitExpr(elseExpr) builder.buildBr(mergeBB) builder.positionAtEnd(of: mergeBB) let phi = builder.buildPhi(FloatType.double) phi.addIncoming([(thenVal, thenBB), (elseVal, elseBB)])

Slide 128

Slide 128 text

case .ifelse(let cond, let thenExpr, let elseExpr): let checkCond = builder.buildFCmp(try emitExpr(cond), FloatType.double.constant(0.0), .orderedNotEqual) let thenBB = builder.currentFunction!.appendBasicBlock(named: "then") let elseBB = builder.currentFunction!.appendBasicBlock(named: "else") let mergeBB = builder.currentFunction!.appendBasicBlock(named: "merge") builder.buildCondBr(condition: checkCond, then: thenBB, else: elseBB) builder.positionAtEnd(of: thenBB) let thenVal = try emitExpr(thenExpr) builder.buildBr(mergeBB) builder.positionAtEnd(of: elseBB) let elseVal = try emitExpr(elseExpr) builder.buildBr(mergeBB) builder.positionAtEnd(of: mergeBB) let phi = builder.buildPhi(FloatType.double) phi.addIncoming([(thenVal, thenBB), (elseVal, elseBB)]) return phi }

Slide 129

Slide 129 text

func emitMain() throws {

Slide 130

Slide 130 text

func emitMain() throws { let mainType = FunctionType(argTypes: [], returnType: VoidType()) let function = builder.addFunction("main", type: mainType)

Slide 131

Slide 131 text

func emitMain() throws { let mainType = FunctionType(argTypes: [], returnType: VoidType()) let function = builder.addFunction("main", type: mainType) let entry = function.appendBasicBlock(named: "entry") builder.positionAtEnd(of: entry) let formatString = builder.buildGlobalStringPtr("%f\n") let printf = emitPrintf()

Slide 132

Slide 132 text

func emitMain() throws { let mainType = FunctionType(argTypes: [], returnType: VoidType()) let function = builder.addFunction("main", type: mainType) let entry = function.appendBasicBlock(named: "entry") builder.positionAtEnd(of: entry) let formatString = builder.buildGlobalStringPtr("%f\n") let printf = emitPrintf() for expr in file.expressions { let val = try emitExpr(expr) builder.buildCall(printf, args: [formatString, val]) }

Slide 133

Slide 133 text

func emitMain() throws { let mainType = FunctionType(argTypes: [], returnType: VoidType()) let function = builder.addFunction("main", type: mainType) let entry = function.appendBasicBlock(named: "entry") builder.positionAtEnd(of: entry) let formatString = builder.buildGlobalStringPtr("%f\n") let printf = emitPrintf() builder.buildRetVoid() } for expr in file.expressions { let val = try emitExpr(expr) builder.buildCall(printf, args: [formatString, val]) }

Slide 134

Slide 134 text

func emitMain() throws { let mainType = FunctionType(argTypes: [], returnType: VoidType()) let function = builder.addFunction("main", type: mainType) let entry = function.appendBasicBlock(named: "entry") builder.positionAtEnd(of: entry) let formatString = builder.buildGlobalStringPtr("%f\n") let printf = emitPrintf() builder.buildRetVoid() } func emit() throws { for extern in file.externs { emitPrototype(extern) } for definition in file.definitions { try emitDefinition(definition) } try emitMain() } for expr in file.expressions { let val = try emitExpr(expr) builder.buildCall(printf, args: [formatString, val]) }

Slide 135

Slide 135 text

%FNP

Slide 136

Slide 136 text

*O%FQUI#MPH1PTUT IBSMBOIBTLJOTDPN .PSF*OGPPO--7. MMWNPSHEPDT 'VMM$PEF HJUIVCDPNUSJMMMBOH,BMFJEPTDPQF