Finished editing PythonLangImpl2.rst doc

This commit is contained in:
Maggie Mari 2012-08-17 12:03:26 -05:00
commit 258efb0518
2 changed files with 327 additions and 282 deletions

View file

@ -39,8 +39,8 @@ We'll start with expressions first:
.. code-block:: python .. code-block:: python
# Base class for all expression nodes. class # Base class for all expression nodes.
ExpressionNode(object): pass class ExpressionNode(object): pass
# Expression class for numeric literals like "1.0". # Expression class for numeric literals like "1.0".
class NumberExpressionNode(ExpressionNode): class NumberExpressionNode(ExpressionNode):
@ -65,8 +65,7 @@ that we'll use in the basic form of the Kaleidoscope language:
.. code-block:: python .. code-block:: python
# Expression class for referencing a variable, # Expression class for referencing a variable, like "a".
like "a".
class VariableExpressionNode(ExpressionNode): class VariableExpressionNode(ExpressionNode):
def __init__(self, name): def __init__(self, name):
self.name = name self.name = name
@ -80,7 +79,7 @@ that we'll use in the basic form of the Kaleidoscope language:
# Expression class for function calls. # Expression class for function calls.
class CallExpressionNode(ExpressionNode): class CallExpressionNode(ExpressionNode):
def __init__self, callee, args): def __init__(self, callee, args):
self.callee = callee self.callee = callee
self.args = args self.args = args
@ -103,9 +102,9 @@ way to talk about functions themselves:
.. code-block:: python .. code-block:: python
# This class represents the "prototype" for a # This class represents the "prototype" for a function, which captures its name,
function, which captures its name, # and its argument names (thus # and its argument names (thus implicitly the number of arguments the function
implicitly the number of arguments the function # takes). # takes).
class PrototypeNode(object): class PrototypeNode(object):
def __init__(self, name, args): def __init__(self, name, args):
self.name = name self.name = name
@ -161,8 +160,8 @@ class with some basic helper routines:
self.Next() self.Next()
# Provide a simple token buffer. Parser.current is the current token the # Provide a simple token buffer. Parser.current is the current token the
# parser is looking at. Parser.Next() reads another token from the lexer # parser is looking at. Parser.Next() reads another token from the lexer and
and # updates Parser.current with its results. # updates Parser.current with its results.
def Next(self): def Next(self):
self.current = self.tokens.next() self.current = self.tokens.next()
@ -173,8 +172,8 @@ to look one token ahead at what the lexer is returning. Every function
in our parser will assume that ``self.current`` is the current token in our parser will assume that ``self.current`` is the current token
that needs to be parsed. Note that the first token is read as soon as that needs to be parsed. Note that the first token is read as soon as
the parser is instantiated. Let us ignore the ``binop_precedence`` the parser is instantiated. Let us ignore the ``binop_precedence``
parameter for now. It will be explained when we start `parsing binary parameter for now. It will be explained when we start parsing binary
operators <#parserbinops>`_. operators.
With these basic helper functions, we can implement the first piece of With these basic helper functions, we can implement the first piece of
our grammar: numeric literals. our grammar: numeric literals.
@ -247,30 +246,29 @@ function calls:
.. code-block:: python .. code-block:: python
# identifierexpr ::= identifier \| identifier '(' # identifierexpr ::= identifier | identifier '(' expression* ')'
expression\* ')'
def ParseIdentifierExpr(self): def ParseIdentifierExpr(self):
identifier_name = self.current.name identifier_name = self.current.name
self.Next() # eat identifier. self.Next() # eat identifier.
if self.current != CharacterToken('('): # Simple variable reference. if self.current != CharacterToken('('): # Simple variable reference.
return VariableExpressionNode(identifier_name); return VariableExpressionNode(identifier_name);
# Call. # Call.
self.Next() # eat '('. self.Next() # eat '('.
args = [] args = []
if self.current != CharacterToken(')'): if self.current != CharacterToken(')'):
while True: while True:
args.append(self.ParseExpression()) args.append(self.ParseExpression())
if self.current == CharacterToken(')'): if self.current == CharacterToken(')'):
break break
elif self.current != CharacterToken(','): elif self.current != CharacterToken(','):
raise RuntimeError('Expected ")" or "," in argument list.') raise RuntimeError('Expected ")" or "," in argument list.')
self.Next() self.Next()
self.Next() # eat ')'. self.Next() # eat ')'.
return CallExpressionNode(identifier_name, args) return CallExpressionNode(identifier_name, args)
@ -295,17 +293,16 @@ primary expression, we need to determine what sort of expression it is:
.. code-block:: python .. code-block:: python
# primary ::= identifierexpr | numberexpr | # primary ::= identifierexpr | numberexpr | parenexpr
parenexpr
def ParsePrimary(self): def ParsePrimary(self):
if isinstance(self.current, IdentifierToken): if isinstance(self.current, IdentifierToken):
return self.ParseIdentifierExpr() return self.ParseIdentifierExpr()
elif isinstance(self.current, NumberToken): elif isinstance(self.current, NumberToken):
return self.ParseNumberExpr(); return self.ParseNumberExpr();
elif self.current == CharacterToken('('): elif self.current == CharacterToken('('):
return self.ParseParenExpr() return self.ParseParenExpr()
else: else:
raise RuntimeError('Unknown token when expecting an expression.') raise RuntimeError('Unknown token when expecting an expression.')
@ -340,21 +337,22 @@ Now is the time to use it:
.. code-block:: python .. code-block:: python
def main(): # Install standard binary operators. def main():
# 1 is lowest possible precedence. 40 is the highest. # Install standard binary operators.
operator_precedence = { # 1 is lowest possible precedence. 40 is the highest.
'<': 10, operator_precedence = {
'+': 20, '<': 10,
'-': 20, '+': 20,
'*': 40 '-': 20,
} '*': 40
}
# Run the main ``interpreter loop``. # Run the main ``interpreter loop``.
while True: while True:
... ...
parser = Parser(Tokenize(raw), operator_precedence) parser = Parser(Tokenize(raw), operator_precedence)
@ -373,8 +371,8 @@ token, or -1 if the token is not a binary operator:
.. code-block:: python .. code-block:: python
# Gets the precedence of the current token, or -1 # Gets the precedence of the current token, or -1 if the token is not a binary
if the token is not a binary # operator. # operator.
def GetCurrentTokenPrecedence(self): def GetCurrentTokenPrecedence(self):
if isinstance(self.current, CharacterToken): if isinstance(self.current, CharacterToken):
return self.binop_precedence.get(self.current.char, -1) return self.binop_precedence.get(self.current.char, -1)
@ -416,7 +414,7 @@ the code passes the expression for ``a`` into ``ParseBinOpRHS`` and the
current token is ``+``. current token is ``+``.
The precedence value passed into ``ParseBinOpRHS`` indicates the \* The precedence value passed into ``ParseBinOpRHS`` indicates the \*
minimal operator precedence\* that the function is allowed to eat. For minimal operator precedence \* that the function is allowed to eat. For
example, if the current pair stream is ``[+, x]`` and ``ParseBinOpRHS`` example, if the current pair stream is ``[+, x]`` and ``ParseBinOpRHS``
is passed in a precedence of 40, it will not consume any tokens (because is passed in a precedence of 40, it will not consume any tokens (because
the precedence of '+' is only 20). With this in mind, ``ParseBinOpRHS`` the precedence of '+' is only 20). With this in mind, ``ParseBinOpRHS``
@ -451,7 +449,7 @@ expression:
.. code-block:: python .. code-block:: python
binary_operator = self.current.char binary_operator = self.current.char
self.Next() # eat the operator. self.Next() # eat the operator.
# Parse the primary expression after the binary operator. # Parse the primary expression after the binary operator.
@ -475,11 +473,11 @@ precedence (which is '+' in this case):
.. code-block:: python .. code-block:: python
# If binary_operator binds less tightly with # If binary_operator binds less tightly with right than the operator after
right than the operator after # right, let the pending operator take # right, let the pending operator take right as its left.
right as its left.
next_precedence = self.GetCurrentTokenPrecedence() next_precedence = self.GetCurrentTokenPrecedence()
if precedence < next_precedence: if precedence < next_precedence:
...
@ -521,8 +519,8 @@ duplicated for context):
.. code-block:: python .. code-block:: python
# If binary_operator binds less tightly with # If binary_operator binds less tightly with right than the operator after
right than the operator after # right, let the pending operator take right as its left. # right, let the pending operator take right as its left.
next_precedence = self.GetCurrentTokenPrecedence() next_precedence = self.GetCurrentTokenPrecedence()
if precedence < next_precedence: if precedence < next_precedence:
right = self.ParseBinOpRHS(right, precedence + 1) right = self.ParseBinOpRHS(right, precedence + 1)
@ -654,7 +652,7 @@ The Driver
The driver for this simply invokes all of the parsing pieces with a The driver for this simply invokes all of the parsing pieces with a
top-level dispatch loop. There isn't much interesting here, so I'll just top-level dispatch loop. There isn't much interesting here, so I'll just
include the top-level loop. See `below <#code>`_ for full code. include the top-level loop. See :ref:`below <code>` for full code.
.. code-block:: python .. code-block:: python
@ -725,6 +723,8 @@ LLVM Intermediate Representation (IR) from the AST.
-------------- --------------
.. _code:
Full Code Listing Full Code Listing
=========================== ===========================
@ -739,8 +739,10 @@ external libraries at all for this.
import re import re
Lexer Lexer
----- -----
.. code-block:: python
# The lexer yields one of these types for each token. # The lexer yields one of these types for each token.
class EOFToken(object): class EOFToken(object):
@ -769,45 +771,54 @@ external libraries at all for this.
return not self == other return not self == other
# Regular expressions that tokens and comments of our language. # Regular expressions that tokens and comments of our language.
REGEX_NUMBER = re.compile('[0-9]+(?:.[0-9]+)?') REGEX_IDENTIFIER = REGEX_NUMBER = re.compile('[0-9]+(?:\.[0-9]+)?')
re.compile('[a-zA-Z][a-zA-Z0-9]\ *') REGEX_COMMENT = re.compile('#.*') REGEX_IDENTIFIER = re.compile('[a-zA-Z][a-zA-Z0-9] *')
REGEX_COMMENT = re.compile('#.*')
def Tokenize(string): while string: # Skip whitespace. if def Tokenize(string):
string[0].isspace(): string = string[1:] continue while string:
# Skip whitespace.
if string[0].isspace():
string = string[1:]
continue
# Run regexes. # Run regexes.
comment_match = REGEX_COMMENT.match(string) comment_match = REGEX_COMMENT.match(string)
number_match = REGEX_NUMBER.match(string) number_match = REGEX_NUMBER.match(string)
identifier_match = REGEX_IDENTIFIER.match(string) identifier_match = REGEX_IDENTIFIER.match(string)
# Check if any of the regexes matched and yield the appropriate result. # Check if any of the regexes matched and yield the appropriate result.
if comment_match: if comment_match:
comment = comment_match.group(0) comment = comment_match.group(0)
string = string[len(comment):] string = string[len(comment):]
elif number_match: elif number_match:
number = number_match.group(0) number = number_match.group(0)
yield NumberToken(float(number)) yield NumberToken(float(number))
string = string[len(number):] string = string[len(number):]
elif identifier_match: elif identifier_match:
identifier = identifier_match.group(0) identifier = identifier_match.group(0)
# Check if we matched a keyword. # Check if we matched a keyword.
if identifier == 'def': if identifier == 'def':
yield DefToken() yield DefToken()
elif identifier == 'extern': elif identifier == 'extern':
yield ExternToken() yield ExternToken()
else: else:
yield IdentifierToken(identifier) yield IdentifierToken(identifier)
string = string[len(identifier):] string = string[len(identifier):]
else: else:
# Yield the ASCII value of the unknown character. # Yield the ASCII value of the unknown character.
yield CharacterToken(string[0]) yield CharacterToken(string[0])
string = string[1:] string = string[1:]
yield EOFToken() yield EOFToken()
Abstract Syntax Tree (aka Parse Tree)
-------------------------------------
Abstract Syntax Tree (aka Parse Tree)
-------------------------------------
.. code-block:: python
# Base class for all expression nodes. # Base class for all expression nodes.
class ExpressionNode(object): class ExpressionNode(object):
@ -845,37 +856,43 @@ external libraries at all for this.
self.args = args self.args = args
# This class represents a function definition itself. # This class represents a function definition itself.
class FunctionNode(object): def __init__(self, prototype, body): class FunctionNode(object):
self.prototype = prototype self.body = body def __init__(self, prototype, body):
self.prototype = prototype
self.body = body
Parser
------
Parser
------
.. code-block:: python
class Parser(object): class Parser(object):
def __init__(self, tokens, binop_precedence): def __init__(self, tokens, binop_precedence):
self.tokens = tokens self.tokens = tokens
self.binop_precedence = binop_precedence self.binop_precedence = binop_precedence
self.Next() self.Next()
# Provide a simple token buffer. Parser.current is the current token the # Provide a simple token buffer. Parser.current is the current token the
# parser is looking at. Parser.Next() reads another token from the lexer # parser is looking at. Parser.Next() reads another token from the lexer and
and # updates Parser.current with its results. # updates Parser.current with its results.
def Next(self): def Next(self):
self.current = self.tokens.next() self.current = self.tokens.next()
# Gets the precedence of the current token, or -1 if the token is not a # Gets the precedence of the current token, or -1 if the token is not a binary
binary # operator. # operator.
def GetCurrentTokenPrecedence(self): def GetCurrentTokenPrecedence(self):
if isinstance(self.current, CharacterToken): if isinstance(self.current, CharacterToken):
return self.binop_precedence.get(self.current.char, -1) return self.binop_precedence.get(self.current.char, -1)
else: else:
return -1 return -1
# identifierexpr ::= identifier \| identifier '(' expression\* ')' # identifierexpr ::= identifier | identifier '(' expression* ')'
def ParseIdentifierExpr(self): def ParseIdentifierExpr(self):
identifier_name = self.current.name identifier_name = self.current.name
self.Next() # eat identifier. self.Next() # eat identifier.
if self.current != CharacterToken('('): # Simple variable reference. if self.current != CharacterToken('('): # Simple variable reference.
@ -896,163 +913,167 @@ external libraries at all for this.
self.Next() # eat ')'. self.Next() # eat ')'.
return CallExpressionNode(identifier_name, args) return CallExpressionNode(identifier_name, args)
# numberexpr ::= number # numberexpr ::= number
def ParseNumberExpr(self): def ParseNumberExpr(self):
result = NumberExpressionNode(self.current.value) result = NumberExpressionNode(self.current.value)
self.Next() # consume the number. self.Next() # consume the number.
return result return result
# parenexpr ::= '(' expression ')' # parenexpr ::= '(' expression ')'
def ParseParenExpr(self): def ParseParenExpr(self):
self.Next() # eat '('. self.Next() # eat '('.
contents = self.ParseExpression() contents = self.ParseExpression()
if self.current != CharacterToken(')'): if self.current != CharacterToken(')'):
raise RuntimeError('Expected ")".') raise RuntimeError('Expected ")".')
self.Next() # eat ')'. self.Next() # eat ')'.
return contents return contents
# primary ::= identifierexpr | numberexpr | parenexpr # primary ::= identifierexpr | numberexpr | parenexpr
def ParsePrimary(self): def ParsePrimary(self):
if isinstance(self.current, IdentifierToken): if isinstance(self.current, IdentifierToken):
return self.ParseIdentifierExpr() return self.ParseIdentifierExpr()
elif isinstance(self.current, NumberToken): elif isinstance(self.current, NumberToken):
return self.ParseNumberExpr() return self.ParseNumberExpr()
elif self.current == CharacterToken('('): elif self.current == CharacterToken('('):
return self.ParseParenExpr() return self.ParseParenExpr()
else: else:
raise RuntimeError('Unknown token when expecting an expression.') raise RuntimeError('Unknown token when expecting an expression.')
# binoprhs ::= (operator primary)* # binoprhs ::= (operator primary)*
def ParseBinOpRHS(self, left, left_precedence): def ParseBinOpRHS(self, left, left_precedence):
# If this is a binary operator, find its precedence. # If this is a binary operator, find its precedence.
while True: while True:
precedence = self.GetCurrentTokenPrecedence() precedence = self.GetCurrentTokenPrecedence()
# If this is a binary operator that binds at least as tightly as the # If this is a binary operator that binds at least as tightly as the
# current one, consume it; otherwise we are done. # current one, consume it; otherwise we are done.
if precedence < left_precedence: if precedence < left_precedence:
return left return left
binary_operator = self.current.char binary_operator = self.current.char
self.Next() # eat the operator. self.Next() # eat the operator.
# Parse the primary expression after the binary operator. # Parse the primary expression after the binary operator.
right = self.ParsePrimary() right = self.ParsePrimary()
# If binary_operator binds less tightly with right than the operator after # If binary_operator binds less tightly with right than the operator after
# right, let the pending operator take right as its left. # right, let the pending operator take right as its left.
next_precedence = self.GetCurrentTokenPrecedence() next_precedence = self.GetCurrentTokenPrecedence()
if precedence < next_precedence: if precedence < next_precedence:
right = self.ParseBinOpRHS(right, precedence + 1) right = self.ParseBinOpRHS(right, precedence + 1)
# Merge left/right. # Merge left/right.
left = BinaryOperatorExpressionNode(binary_operator, left, right) left = BinaryOperatorExpressionNode(binary_operator, left, right)
# expression ::= primary binoprhs # expression ::= primary binoprhs
def ParseExpression(self): def ParseExpression(self):
left = self.ParsePrimary() left = self.ParsePrimary()
return self.ParseBinOpRHS(left, 0) return self.ParseBinOpRHS(left, 0)
# prototype ::= id '(' id\* ')' # prototype ::= id '(' id* ')'
def ParsePrototype(self): def ParsePrototype(self):
if not isinstance(self.current, IdentifierToken): if not isinstance(self.current, IdentifierToken):
raise RuntimeError('Expected function name in prototype.') raise RuntimeError('Expected function name in prototype.')
function_name = self.current.name function_name = self.current.name
self.Next() # eat function name. self.Next() # eat function name.
if self.current != CharacterToken('('): if self.current != CharacterToken('('):
raise RuntimeError('Expected "(" in prototype.') raise RuntimeError('Expected "(" in prototype.')
self.Next() # eat '('. self.Next() # eat '('.
arg_names = [] arg_names = []
while isinstance(self.current, IdentifierToken): while isinstance(self.current, IdentifierToken):
arg_names.append(self.current.name) arg_names.append(self.current.name)
self.Next() self.Next()
if self.current != CharacterToken(')'): if self.current != CharacterToken(')'):
raise RuntimeError('Expected ")" in prototype.') raise RuntimeError('Expected ")" in prototype.')
# Success. # Success.
self.Next() # eat ')'. self.Next() # eat ')'.
return PrototypeNode(function_name, arg_names) return PrototypeNode(function_name, arg_names)
# definition ::= 'def' prototype expression # definition ::= 'def' prototype expression
def ParseDefinition(self): def ParseDefinition(self):
self.Next() # eat def. self.Next() # eat def.
proto = self.ParsePrototype() proto = self.ParsePrototype()
body = self.ParseExpression() body = self.ParseExpression()
return FunctionNode(proto, body) return FunctionNode(proto, body)
# toplevelexpr ::= expression # toplevelexpr ::= expression
def ParseTopLevelExpr(self): def ParseTopLevelExpr(self):
proto = PrototypeNode('', []) proto = PrototypeNode('', [])
return FunctionNode(proto, self.ParseExpression()) return FunctionNode(proto, self.ParseExpression())
# external ::= 'extern' prototype # external ::= 'extern' prototype
def ParseExtern(self): def ParseExtern(self):
self.Next() #eat extern. self.Next() # eat extern.
return self.ParsePrototype() return self.ParsePrototype()
# Top-Level parsing # Top-Level parsing
def HandleDefinition(self): def HandleDefinition(self):
self.Handle(self.ParseDefinition, 'Parsed a function definition.') self.Handle(self.ParseDefinition, 'Parsed a function definition.')
def HandleExtern(self): def HandleExtern(self):
self.Handle(self.ParseExtern, 'Parsed an extern.') self.Handle(self.ParseExtern, 'Parsed an extern.')
def HandleTopLevelExpression(self): def HandleTopLevelExpression(self):
self.Handle(self.ParseTopLevelExpr, 'Parsed a top-level expression.') self.Handle(self.ParseTopLevelExpr, 'Parsed a top-level expression.')
def Handle(self, function, message): def Handle(self, function, message):
try:
function()
print message
except Exception, e:
print 'Error:', e
try: try:
self.Next() # Skip for error recovery. function()
except: print message
pass except Exception, e:
print 'Error:', e
try:
self.Next() # Skip for error recovery.
except:
pass
Main driver code.
-----------------
Main driver code.
-----------------
.. code-block:: python
def main(): def main():
# Install standard binary operators. # Install standard binary operators.
# 1 is lowest possible precedence. 40 is the highest. # 1 is lowest possible precedence. 40 is the highest.
operator_precedence = { operator_precedence = {
'<': 10, '<': 10,
'+':20, '+': 20,
'-': 20, '-': 20,
'*': 40 '*': 40
} }
# Run the main "interpreter loop". # Run the main "interpreter loop".
while True:
print 'ready>',
try:
raw = raw_input()
except KeyboardInterrupt:
return
parser = Parser(Tokenize(raw), operator_precedence)
while True: while True:
# top ::= definition | external | expression | EOF print 'ready>',
if isinstance(parser.current, EOFToken): try:
break raw = raw_input()
if isinstance(parser.current, DefToken): except KeyboardInterrupt:
parser.HandleDefinition() return
elif isinstance(parser.current, ExternToken):
parser.HandleExtern()
else:
parser.HandleTopLevelExpression()
if ==name__ == '__main__': parser = Parser(Tokenize(raw), operator_precedence)
while True:
# top ::= definition | external | expression | EOF
if isinstance(parser.current, EOFToken):
break
if isinstance(parser.current, DefToken):
parser.HandleDefinition()
elif isinstance(parser.current, ExternToken):
parser.HandleExtern()
else:
parser.HandleTopLevelExpression()
if __name__ == '__main__':
main() main()

View file

@ -287,15 +287,21 @@ this:
try: try:
self.Next() # Skip for error recovery. self.Next() # Skip for error recovery.
except: except:
pass {% endhighlight %} pass
Recall that we compile top-level expressions into a self-contained LLVM Recall that we compile top-level expressions into a self-contained LLVM
function that takes no arguments and returns the computed double. function that takes no arguments and returns the computed double.
With just these two changes, lets see how Kaleidoscope works now! With just these two changes, lets see how Kaleidoscope works now!
ready> 4+5 Read a top level expression: define .. code-block:: bash
double @0() { entry: ret double 9.000000e+00 }
ready> 4+5
Read a top level expression:
define double @0() {
entry:
ret double 9.000000e+00
}
Evaluated to: 9.0 Evaluated to: 9.0
@ -307,16 +313,24 @@ synthesize for each top-level expression that is typed in. This
demonstrates very basic functionality, but can we do more? demonstrates very basic functionality, but can we do more?
.. code-block:: python .. code-block:: bash
ready> def testfunc(x y) x + y\*2 Read a function ready> def testfunc(x y) x + y*2
definition: define double @testfunc(double %x, double %y) { entry: Read a function definition:
%multmp = fmul double %y, 2.000000e+00 ; <double> [#uses=1] %addtmp = fadd double define double @testfunc(double %x, double %y) {
%multmp, %x ; <double> [#uses=1] ret double %addtmp } entry:
%multmp = fmul double %y, 2.000000e+00 ; <double> [#uses=1]
%addtmp = fadd double %multmp, %x ; <double> [#uses=1]
ret double %addtmp
}
ready> testfunc(4, 10) Read a top level expression: define double @0() { ready> testfunc(4, 10)
entry: %calltmp = call double @testfunc(double 4.000000e+00, double Read a top level expression:
1.000000e+01) ; <double> [#uses=1] ret double %calltmp } define double @0() {
entry:
%calltmp = call double @testfunc(double 4.000000e+00, double 1.000000e+01) ; <double> [#uses=1]
ret double %calltmp
}
*Evaluated to: 24.0* *Evaluated to: 24.0*
@ -339,23 +353,33 @@ anonymous functions, you should get the idea by now :) :
.. code-block:: bash .. code-block:: bash
ready> extern sin(x) Read an extern: declare double ready> extern sin(x)
@sin(double) Read an extern:
declare double @sin(double)
ready> extern cos(x) Read an extern: declare double @cos(double) ready> extern cos(x)
Read an extern:
declare double @cos(double)
ready> sin(1.0) *Evaluated to: 0.841470984808* ready> sin(1.0)
*Evaluated to: 0.841470984808*
ready> def foo(x) sin(x)\ *sin(x) + cos(x)*\ cos(x) Read a function ready> def foo(x) sin(x) *sin(x) + cos(x)* cos(x)
definition: define double @foo(double %x) { entry: %calltmp = call Read a function definition:
double @sin(double %x) ; <double> [#uses=1] %calltmp1 = call double @sin(double define double @foo(double %x) {
%x) ; <double> [#uses=1] %multmp = fmul double %calltmp, %calltmp1 ; <double> [#uses=1] entry:
%calltmp2 = call double @cos(double %x) ; <double> [#uses=1] %calltmp3 = call %calltmp = call double @sin(double %x) ; <double> [#uses=1]
double @cos(double %x) ; <double> [#uses=1] %multmp4 = fmul double %calltmp2, %calltmp1 = call double @sin(double %x) ; <double> [#uses=1]
%calltmp3 ; <double> [#uses=1] %addtmp = fadd double %multmp, %multmp4 ; %multmp = fmul double %calltmp, %calltmp1 ; <double> [#uses=1]
<double> [#uses=1] ret double %addtmp } %calltmp2 = call double @cos(double %x) ; <double> [#uses=1]
%calltmp3 = call double @cos(double %x) ; <double> [#uses=1]
%multmp4 = fmul double %calltmp2, %calltmp3 ; <double> [#uses=1]
%addtmp = fadd double %multmp, %multmp4 ; <double> [#uses=1]
ret double %addtmp
}
ready> foo(4.0) *Evaluated to: 1.000000* ready> foo(4.0)
*Evaluated to: 1.000000*