Removed more extraneous code tags from docs.
This commit is contained in:
parent
8e00cd7e66
commit
1b67d32f4b
4 changed files with 10 additions and 20 deletions
|
|
@ -403,13 +403,11 @@ example, we can create a C file with the following simple function:
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
double putchard(double x) {
|
double putchard(double x) {
|
||||||
putchar((char)x); return 0; } {%
|
putchar((char)x); return 0; }
|
||||||
endhighlight %}
|
|
||||||
|
|
||||||
We can then compile this into a shared library with GCC:
|
We can then compile this into a shared library with GCC:
|
||||||
|
|
||||||
gcc -shared -fPIC -o putchard.so putchard.c {%
|
gcc -shared -fPIC -o putchard.so putchard.c
|
||||||
endhighlight %}
|
|
||||||
|
|
||||||
Now we can load this library into the Python process using
|
Now we can load this library into the Python process using
|
||||||
``llvm.core.load_library_permanently`` and access it from Kaleidoscope
|
``llvm.core.load_library_permanently`` and access it from Kaleidoscope
|
||||||
|
|
|
||||||
|
|
@ -601,8 +601,7 @@ expression for the loop value:
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
def CodeGen(self): # Emit the start code first,
|
def CodeGen(self): # Emit the start code first,
|
||||||
without 'variable' in scope. start_value = self.start.CodeGen() {%
|
without 'variable' in scope. start_value = self.start.CodeGen()
|
||||||
endhighlight %}
|
|
||||||
|
|
||||||
With this out of the way, the next step is to set up the LLVM basic
|
With this out of the way, the next step is to set up the LLVM basic
|
||||||
block for the start of the loop body. In the case above, the whole loop
|
block for the start of the loop body. In the case above, the whole loop
|
||||||
|
|
|
||||||
|
|
@ -91,8 +91,7 @@ keywords:
|
||||||
BinaryToken(object): pass class UnaryToken(object): pass ... def
|
BinaryToken(object): pass class UnaryToken(object): pass ... def
|
||||||
Tokenize(string): ... elif identifier == 'in': yield InToken() elif
|
Tokenize(string): ... elif identifier == 'in': yield InToken() elif
|
||||||
identifier == 'binary': yield BinaryToken() elif identifier == 'unary':
|
identifier == 'binary': yield BinaryToken() elif identifier == 'unary':
|
||||||
yield UnaryToken() else: yield IdentifierToken(identifier) {%
|
yield UnaryToken() else: yield IdentifierToken(identifier)
|
||||||
endhighlight %}
|
|
||||||
|
|
||||||
This just adds lexer support for the unary and binary keywords, like we
|
This just adds lexer support for the unary and binary keywords, like we
|
||||||
did in `previous chapters <PythonLangImpl5.html#iflexer>`_. One nice
|
did in `previous chapters <PythonLangImpl5.html#iflexer>`_. One nice
|
||||||
|
|
@ -446,8 +445,7 @@ denser the character:
|
||||||
' else if d > 4 then putchard(46) # '.' else if d > 2 then putchard(43)
|
' else if d > 4 then putchard(46) # '.' else if d > 2 then putchard(43)
|
||||||
# '+' else putchard(42); # '*' ... ready> printdensity(1):
|
# '+' else putchard(42); # '*' ... ready> printdensity(1):
|
||||||
printdensity(2): printdensity(3) : printdensity(4): printdensity(5):
|
printdensity(2): printdensity(3) : printdensity(4): printdensity(5):
|
||||||
printdensity(9): putchard(10)*\ ++.. Evaluated to 0.000000 {%
|
printdensity(9): putchard(10)*\ ++.. Evaluated to 0.000000
|
||||||
endhighlight %}
|
|
||||||
|
|
||||||
Based on these simple primitive operations, we can start to define more
|
Based on these simple primitive operations, we can start to define more
|
||||||
interesting things. For example, here's a little function that solves
|
interesting things. For example, here's a little function that solves
|
||||||
|
|
|
||||||
|
|
@ -350,8 +350,7 @@ from the stack slot:
|
||||||
def CodeGen(self): if self.name in
|
def CodeGen(self): if self.name in
|
||||||
g_named_values: return
|
g_named_values: return
|
||||||
g_llvm_builder.load(g_named_values[self.name], self.name) else:
|
g_llvm_builder.load(g_named_values[self.name], self.name) else:
|
||||||
raise RuntimeError('Unknown variable name: ' + self.name) {%
|
raise RuntimeError('Unknown variable name: ' + self.name)
|
||||||
endhighlight %}
|
|
||||||
|
|
||||||
As you can see, this is pretty straightforward. Now we need to update
|
As you can see, this is pretty straightforward. Now we need to update
|
||||||
the things that define the variables to set up the alloca. We'll start
|
the things that define the variables to set up the alloca. We'll start
|
||||||
|
|
@ -431,8 +430,7 @@ get good codegen once again:
|
||||||
g_llvm_pass_manager.add(PASS_PROMOTE_MEMORY_TO_REGISTER) # Do
|
g_llvm_pass_manager.add(PASS_PROMOTE_MEMORY_TO_REGISTER) # Do
|
||||||
simple "peephole" optimizations and bit-twiddling optzns.
|
simple "peephole" optimizations and bit-twiddling optzns.
|
||||||
g_llvm_pass_manager.add(PASS_INSTRUCTION_COMBINING) # Reassociate
|
g_llvm_pass_manager.add(PASS_INSTRUCTION_COMBINING) # Reassociate
|
||||||
expressions. g_llvm_pass_manager.add(PASS_REASSOCIATE) {%
|
expressions. g_llvm_pass_manager.add(PASS_REASSOCIATE)
|
||||||
endhighlight %}
|
|
||||||
|
|
||||||
It is interesting to see what the code looks like before and after the
|
It is interesting to see what the code looks like before and after the
|
||||||
mem2reg optimization runs. For example, this is the before/after code
|
mem2reg optimization runs. For example, this is the before/after code
|
||||||
|
|
@ -448,8 +446,7 @@ get good codegen once again:
|
||||||
%subtmp5 = fsub double %x4, 2.000000e+00 %calltmp6 = call double
|
%subtmp5 = fsub double %x4, 2.000000e+00 %calltmp6 = call double
|
||||||
@fib(double %subtmp5) %addtmp = fadd double %calltmp, %calltmp6 br label
|
@fib(double %subtmp5) %addtmp = fadd double %calltmp, %calltmp6 br label
|
||||||
%ifcont ifcont: ; preds = %else, %then %iftmp = phi double [
|
%ifcont ifcont: ; preds = %else, %then %iftmp = phi double [
|
||||||
1.000000e+00, %then ], [ %addtmp, %else ] ret double %iftmp } {%
|
1.000000e+00, %then ], [ %addtmp, %else ] ret double %iftmp }
|
||||||
endhighlight %}
|
|
||||||
|
|
||||||
Here there is only one variable (x, the input argument) but you can
|
Here there is only one variable (x, the input argument) but you can
|
||||||
still see the extremely simple-minded code generation strategy we are
|
still see the extremely simple-minded code generation strategy we are
|
||||||
|
|
@ -517,8 +514,7 @@ step is to set a precedence:
|
||||||
def main(): ... # Install standard binary
|
def main(): ... # Install standard binary
|
||||||
operators. # 1 is lowest possible precedence. 40 is the highest.
|
operators. # 1 is lowest possible precedence. 40 is the highest.
|
||||||
g_binop_precedence['='] = 2 g_binop_precedence['<'] = 10
|
g_binop_precedence['='] = 2 g_binop_precedence['<'] = 10
|
||||||
g_binop_precedence['+'] = 20 g_binop_precedence['-'] = 20 {%
|
g_binop_precedence['+'] = 20 g_binop_precedence['-'] = 20
|
||||||
endhighlight %}
|
|
||||||
|
|
||||||
Now that the parser knows the precedence of the binary operator, it
|
Now that the parser knows the precedence of the binary operator, it
|
||||||
takes care of all the parsing and AST generation. We just need to
|
takes care of all the parsing and AST generation. We just need to
|
||||||
|
|
@ -529,8 +525,7 @@ step is to set a precedence:
|
||||||
special case for '=' because we don't want to emit the LHS as an #
|
special case for '=' because we don't want to emit the LHS as an #
|
||||||
expression. if self.operator == '=': # Assignment requires the LHS to be
|
expression. if self.operator == '=': # Assignment requires the LHS to be
|
||||||
an identifier. if not isinstance(self.left, VariableExpressionNode):
|
an identifier. if not isinstance(self.left, VariableExpressionNode):
|
||||||
raise RuntimeError('Destination of "=" must be a variable.') {%
|
raise RuntimeError('Destination of "=" must be a variable.')
|
||||||
endhighlight %}
|
|
||||||
|
|
||||||
Unlike the rest of the binary operators, our assignment operator doesn't
|
Unlike the rest of the binary operators, our assignment operator doesn't
|
||||||
follow the "emit LHS, emit RHS, do computation" model. As such, it is
|
follow the "emit LHS, emit RHS, do computation" model. As such, it is
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue