Add notebook: llvm_cbuilder quick tour
This commit is contained in:
parent
9ccc6782c7
commit
7f84ecbe3b
2 changed files with 586 additions and 0 deletions
586
notebook/llvm_cbuilder_intro.ipynb
Normal file
586
notebook/llvm_cbuilder_intro.ipynb
Normal file
|
|
@ -0,0 +1,586 @@
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"name": "llvm_cbuilder_intro"
|
||||||
|
},
|
||||||
|
"nbformat": 2,
|
||||||
|
"worksheets": [
|
||||||
|
{
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"source": [
|
||||||
|
"llvm_cbuilder: A Quick Tour",
|
||||||
|
"---------------------------",
|
||||||
|
"",
|
||||||
|
"Writing code generation logic in pure llvmpy requires one to think like a compiler -- ",
|
||||||
|
"dealing with basic-blocks, branches, SSA, etc.",
|
||||||
|
"The resulting code looks like assembly code, with no apparent hint about the control-flow.",
|
||||||
|
"",
|
||||||
|
"llvm_cbuilder is originally designed to simplify the translation of C code into llvmpy.",
|
||||||
|
"It provides a simple API for mimicking C programming in Python.",
|
||||||
|
"With llvm_cbulder, one can write very low-level code, probably even lower-level than C.",
|
||||||
|
"At the same time, one can use if-else, loop, structures and a bit of OOP."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"source": [
|
||||||
|
"A Simple Example",
|
||||||
|
"----------------",
|
||||||
|
"",
|
||||||
|
"Let's see some action.",
|
||||||
|
"We will define a function that calculates the square of a double-precision float."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"collapsed": true,
|
||||||
|
"input": [
|
||||||
|
"from llvm.core import *",
|
||||||
|
"from llvm_cbuilder import *",
|
||||||
|
"import llvm_cbuilder.shortnames as C",
|
||||||
|
"",
|
||||||
|
"class Square(CDefinition):",
|
||||||
|
" # prototype: double square(double x)",
|
||||||
|
" _name_ = 'square' # function name",
|
||||||
|
" _retty_ = C.double",
|
||||||
|
" _argtys_ = [ ('x', C.double) ]",
|
||||||
|
" ",
|
||||||
|
" def body(self, x):",
|
||||||
|
" y = x * x # just write out the expression",
|
||||||
|
" self.ret(y)"
|
||||||
|
],
|
||||||
|
"language": "python",
|
||||||
|
"outputs": [],
|
||||||
|
"prompt_number": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"source": [
|
||||||
|
"Notice how numerical expressions can be written naturally."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"source": [
|
||||||
|
"Let's see the emitted code:"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"collapsed": false,
|
||||||
|
"input": [
|
||||||
|
"m = Module.new('my_module')",
|
||||||
|
"llvm_square = Square()(m) # define square() in my_module",
|
||||||
|
"print(m)"
|
||||||
|
],
|
||||||
|
"language": "python",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"output_type": "stream",
|
||||||
|
"stream": "stdout",
|
||||||
|
"text": [
|
||||||
|
"; ModuleID = 'my_module'",
|
||||||
|
"",
|
||||||
|
"define double @square(double %x) {",
|
||||||
|
"decl:",
|
||||||
|
" %x1 = alloca double",
|
||||||
|
" br label %body",
|
||||||
|
"",
|
||||||
|
"body: ; preds = %decl",
|
||||||
|
" store double %x, double* %x1",
|
||||||
|
" %0 = load double* %x1",
|
||||||
|
" %1 = load double* %x1",
|
||||||
|
" %2 = fmul double %0, %1",
|
||||||
|
" ret double %2",
|
||||||
|
"}",
|
||||||
|
""
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"prompt_number": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"source": [
|
||||||
|
"Let's generate a ctype function object to call `square()` in the Python code:"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"collapsed": false,
|
||||||
|
"input": [
|
||||||
|
"exe = CExecutor(m)",
|
||||||
|
"square = exe.get_ctype_function(llvm_square, \"double, double\")",
|
||||||
|
"result = square(1.2)",
|
||||||
|
"print(result)"
|
||||||
|
],
|
||||||
|
"language": "python",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"output_type": "stream",
|
||||||
|
"stream": "stdout",
|
||||||
|
"text": [
|
||||||
|
"1.44"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"prompt_number": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"source": [
|
||||||
|
"Control Flow Constructs",
|
||||||
|
"-----------------------",
|
||||||
|
"",
|
||||||
|
"The main strength of llvm_cbuilder is the control-flow constructs. ",
|
||||||
|
"They use the python \"with\" statement to setup new code blocks to",
|
||||||
|
"contain different paths of the control flow.",
|
||||||
|
"",
|
||||||
|
"The following example demonstrates both the if-else and loop contructs:"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"collapsed": true,
|
||||||
|
"input": [
|
||||||
|
"class IsPrime(CDefinition):",
|
||||||
|
" # prototype int isprime(int x)",
|
||||||
|
" _name_ = 'isprime'",
|
||||||
|
" _retty_ = C.int",
|
||||||
|
" _argtys_ = [ ('x', C.int) ]",
|
||||||
|
" ",
|
||||||
|
" def body(self, x):",
|
||||||
|
" two = self.constant(C.int, 2)",
|
||||||
|
" true = one = self.constant(C.int, 1)",
|
||||||
|
" false = zero = self.constant(C.int, 0)",
|
||||||
|
" ",
|
||||||
|
" with self.ifelse( x <= two ) as ifelse:",
|
||||||
|
" with ifelse.then():",
|
||||||
|
" self.ret(true)",
|
||||||
|
" ",
|
||||||
|
" with self.ifelse( (x % two) == zero ) as ifelse:",
|
||||||
|
" with ifelse.then():",
|
||||||
|
" self.ret(false)",
|
||||||
|
" ",
|
||||||
|
" idx = self.var(C.int, 3, name='idx')",
|
||||||
|
" with self.loop() as loop:",
|
||||||
|
" with loop.condition() as setcond:",
|
||||||
|
" setcond( idx < x )",
|
||||||
|
" ",
|
||||||
|
" with loop.body():",
|
||||||
|
" with self.ifelse( (x % idx) == zero ) as ifelse:",
|
||||||
|
" with ifelse.then():",
|
||||||
|
" self.ret(false)",
|
||||||
|
" idx += two",
|
||||||
|
" self.ret(true)"
|
||||||
|
],
|
||||||
|
"language": "python",
|
||||||
|
"outputs": [],
|
||||||
|
"prompt_number": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"source": [
|
||||||
|
"The code above is quite verbose.",
|
||||||
|
"It is like writing in Pascal or Ada. ",
|
||||||
|
"But, it is still easier than writing in llvmpy directly.",
|
||||||
|
"Take a look at the generated LLVM IR below."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"collapsed": false,
|
||||||
|
"input": [
|
||||||
|
"llvm_isprime = IsPrime()(m)",
|
||||||
|
"print(llvm_isprime)"
|
||||||
|
],
|
||||||
|
"language": "python",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"output_type": "stream",
|
||||||
|
"stream": "stdout",
|
||||||
|
"text": [
|
||||||
|
"",
|
||||||
|
"define i32 @isprime(i32 %x) {",
|
||||||
|
"decl:",
|
||||||
|
" %x1 = alloca i32",
|
||||||
|
" %idx = alloca i32",
|
||||||
|
" br label %body",
|
||||||
|
"",
|
||||||
|
"body: ; preds = %decl",
|
||||||
|
" store i32 %x, i32* %x1",
|
||||||
|
" %0 = load i32* %x1",
|
||||||
|
" %1 = icmp sle i32 %0, 2",
|
||||||
|
" br i1 %1, label %if.then, label %if.else",
|
||||||
|
"",
|
||||||
|
"if.then: ; preds = %body",
|
||||||
|
" ret i32 1",
|
||||||
|
"",
|
||||||
|
"if.else: ; preds = %body",
|
||||||
|
" br label %if.end",
|
||||||
|
"",
|
||||||
|
"if.end: ; preds = %if.else",
|
||||||
|
" %2 = load i32* %x1",
|
||||||
|
" %3 = srem i32 %2, 2",
|
||||||
|
" %4 = icmp eq i32 %3, 0",
|
||||||
|
" br i1 %4, label %if.then2, label %if.else3",
|
||||||
|
"",
|
||||||
|
"if.then2: ; preds = %if.end",
|
||||||
|
" ret i32 0",
|
||||||
|
"",
|
||||||
|
"if.else3: ; preds = %if.end",
|
||||||
|
" br label %if.end4",
|
||||||
|
"",
|
||||||
|
"if.end4: ; preds = %if.else3",
|
||||||
|
" store i32 3, i32* %idx",
|
||||||
|
" br label %loop.cond",
|
||||||
|
"",
|
||||||
|
"loop.cond: ; preds = %if.end7, %if.end4",
|
||||||
|
" %5 = load i32* %idx",
|
||||||
|
" %6 = load i32* %x1",
|
||||||
|
" %7 = icmp slt i32 %5, %6",
|
||||||
|
" br i1 %7, label %loop.body, label %loop.end",
|
||||||
|
"",
|
||||||
|
"loop.body: ; preds = %loop.cond",
|
||||||
|
" %8 = load i32* %x1",
|
||||||
|
" %9 = load i32* %idx",
|
||||||
|
" %10 = srem i32 %8, %9",
|
||||||
|
" %11 = icmp eq i32 %10, 0",
|
||||||
|
" br i1 %11, label %if.then5, label %if.else6",
|
||||||
|
"",
|
||||||
|
"loop.end: ; preds = %loop.cond",
|
||||||
|
" ret i32 1",
|
||||||
|
"",
|
||||||
|
"if.then5: ; preds = %loop.body",
|
||||||
|
" ret i32 0",
|
||||||
|
"",
|
||||||
|
"if.else6: ; preds = %loop.body",
|
||||||
|
" br label %if.end7",
|
||||||
|
"",
|
||||||
|
"if.end7: ; preds = %if.else6",
|
||||||
|
" %12 = load i32* %idx",
|
||||||
|
" %13 = add i32 %12, 2",
|
||||||
|
" store i32 %13, i32* %idx",
|
||||||
|
" br label %loop.cond",
|
||||||
|
"}",
|
||||||
|
""
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"prompt_number": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"source": [
|
||||||
|
"We'll setup a ctype function object to try it out:"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"collapsed": false,
|
||||||
|
"input": [
|
||||||
|
"isprime = exe.get_ctype_function(llvm_isprime, 'int, int')",
|
||||||
|
"prime_100 = filter(isprime, range(2, 100))",
|
||||||
|
"print(prime_100)"
|
||||||
|
],
|
||||||
|
"language": "python",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"output_type": "stream",
|
||||||
|
"stream": "stdout",
|
||||||
|
"text": [
|
||||||
|
"[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"prompt_number": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"source": [
|
||||||
|
"Structures",
|
||||||
|
"----------",
|
||||||
|
"",
|
||||||
|
"It is possible to create structures in llvm_cbuilder. ",
|
||||||
|
"Beware that structures in LLVM are unlike those in C.",
|
||||||
|
"LLVM type system allows structures to be literal or identified.",
|
||||||
|
"Literal structures are equivalent iff they have the same elements.",
|
||||||
|
"Identified structures are equivalent iff they have the same name.",
|
||||||
|
"In llvm_cbuilder, all structures are, by default, literal types.",
|
||||||
|
"",
|
||||||
|
"Here's an example:"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"collapsed": true,
|
||||||
|
"input": [
|
||||||
|
"class Vector2D(CStruct):",
|
||||||
|
" _fields_ = [",
|
||||||
|
" ('x', C.float),",
|
||||||
|
" ('y', C.float),",
|
||||||
|
" ]"
|
||||||
|
],
|
||||||
|
"language": "python",
|
||||||
|
"outputs": [],
|
||||||
|
"prompt_number": 7
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"source": [
|
||||||
|
"That's all you need for a structure. Very much like defining structures with ctypes.",
|
||||||
|
"",
|
||||||
|
"We can also bind methods to structures which inline code to the caller."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"collapsed": true,
|
||||||
|
"input": [
|
||||||
|
"class Vector2D(CStruct):",
|
||||||
|
" _fields_ = [",
|
||||||
|
" ('x', C.float),",
|
||||||
|
" ('y', C.float),",
|
||||||
|
" ]",
|
||||||
|
" ",
|
||||||
|
" def add(self, other):",
|
||||||
|
" self.x += other.x",
|
||||||
|
" self.y += other.y"
|
||||||
|
],
|
||||||
|
"language": "python",
|
||||||
|
"outputs": [],
|
||||||
|
"prompt_number": 8
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"source": [
|
||||||
|
"Setup a a test function:"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"collapsed": true,
|
||||||
|
"input": [
|
||||||
|
"class TestVector(CDefinition):",
|
||||||
|
" _name_ = 'testvector'",
|
||||||
|
" _retty_ = C.float",
|
||||||
|
" _argtys_ = [('x', C.float), ",
|
||||||
|
" ('y', C.float)] ",
|
||||||
|
" ",
|
||||||
|
" def body(self, x, y):",
|
||||||
|
" va = self.var(Vector2D)",
|
||||||
|
" vb = self.var(Vector2D)",
|
||||||
|
" va.x.assign(self.constant(C.float, 10))",
|
||||||
|
" va.y.assign(self.constant(C.float, 20))",
|
||||||
|
" vb.x.assign(x)",
|
||||||
|
" vb.y.assign(y)",
|
||||||
|
" ",
|
||||||
|
" va.add(vb)",
|
||||||
|
" ",
|
||||||
|
" return self.ret(va.x * va.y)",
|
||||||
|
" "
|
||||||
|
],
|
||||||
|
"language": "python",
|
||||||
|
"outputs": [],
|
||||||
|
"prompt_number": 9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"collapsed": false,
|
||||||
|
"input": [
|
||||||
|
"llvm_testvec = TestVector()(m)",
|
||||||
|
"testvec = exe.get_ctype_function(llvm_testvec, \"float, float, float\")",
|
||||||
|
"print(testvec(-8, 5)) # should output 50"
|
||||||
|
],
|
||||||
|
"language": "python",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"output_type": "stream",
|
||||||
|
"stream": "stdout",
|
||||||
|
"text": [
|
||||||
|
"50.0"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"prompt_number": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"source": [
|
||||||
|
"Generic Programming",
|
||||||
|
"-------------------",
|
||||||
|
"",
|
||||||
|
"llvm_cbuilder supports generic function (or template function for C++).",
|
||||||
|
"When a `CDefinition` defines the `specialize` class method,",
|
||||||
|
"its constructor will invoke `specialize`.",
|
||||||
|
"All parameters passed to the constructor are forwarded to `specialize`.",
|
||||||
|
"",
|
||||||
|
"The constructor of a generic CDefinition creates a new dynamic class with the original CDefinition subclass as the parent.",
|
||||||
|
"Thus, `specialize` can modify class attributes without affecting the parent."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"collapsed": false,
|
||||||
|
"input": [
|
||||||
|
"class GenericSquare(CDefinition):",
|
||||||
|
" @classmethod",
|
||||||
|
" def specialize(cls, data_type):",
|
||||||
|
" cls._name_ = '.'.join(['square', str(data_type)]) # set function name",
|
||||||
|
" cls._retty_ = data_type # set return type",
|
||||||
|
" cls._argtys_ = [ ('x', data_type) ] # set argument type",
|
||||||
|
" ",
|
||||||
|
" def body(self, x):",
|
||||||
|
" y = x * x # just write out the expression",
|
||||||
|
" self.ret(y)",
|
||||||
|
" ",
|
||||||
|
"llvm_square_int = GenericSquare(data_type=C.int)(m)",
|
||||||
|
"llvm_square_float = GenericSquare(data_type=C.float)(m)",
|
||||||
|
"",
|
||||||
|
"print(llvm_square_int)",
|
||||||
|
"print(llvm_square_float)"
|
||||||
|
],
|
||||||
|
"language": "python",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"output_type": "stream",
|
||||||
|
"stream": "stdout",
|
||||||
|
"text": [
|
||||||
|
"",
|
||||||
|
"define i32 @square.i32(i32 %x) {",
|
||||||
|
"decl:",
|
||||||
|
" %x1 = alloca i32",
|
||||||
|
" br label %body",
|
||||||
|
"",
|
||||||
|
"body: ; preds = %decl",
|
||||||
|
" store i32 %x, i32* %x1",
|
||||||
|
" %0 = load i32* %x1",
|
||||||
|
" %1 = load i32* %x1",
|
||||||
|
" %2 = mul i32 %0, %1",
|
||||||
|
" ret i32 %2",
|
||||||
|
"}",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"define float @square.float(float %x) {",
|
||||||
|
"decl:",
|
||||||
|
" %x1 = alloca float",
|
||||||
|
" br label %body",
|
||||||
|
"",
|
||||||
|
"body: ; preds = %decl",
|
||||||
|
" store float %x, float* %x1",
|
||||||
|
" %0 = load float* %x1",
|
||||||
|
" %1 = load float* %x1",
|
||||||
|
" %2 = fmul float %0, %1",
|
||||||
|
" ret float %2",
|
||||||
|
"}",
|
||||||
|
""
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"prompt_number": 11
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"source": [
|
||||||
|
"External Functions",
|
||||||
|
"------------------",
|
||||||
|
"",
|
||||||
|
"`CExternal` is a convenient class to help accessing externally-defined functions.",
|
||||||
|
"",
|
||||||
|
"We define an external interface to `sqrtf()` in libm."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"collapsed": true,
|
||||||
|
"input": [
|
||||||
|
"class LibM(CExternal):",
|
||||||
|
" sqrtf = Type.function(C.float, [C.float])"
|
||||||
|
],
|
||||||
|
"language": "python",
|
||||||
|
"outputs": [],
|
||||||
|
"prompt_number": 12
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"source": [
|
||||||
|
"All class attributes that are `llvm.core.FunctionType` in `CExternal` ",
|
||||||
|
"are converted to a `CFunc` instance.",
|
||||||
|
"`CFunc` instances are callable.",
|
||||||
|
"`CFunc.__call__` generates code that perform the corresponding LLVM function call.",
|
||||||
|
"",
|
||||||
|
"The following example demonstrates the usage of `CExternal` and `CFunc`."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"collapsed": false,
|
||||||
|
"input": [
|
||||||
|
"class TestSqrtf(CDefinition):",
|
||||||
|
" _name_ = 'test_sqrtf'",
|
||||||
|
" _retty_ = C.float",
|
||||||
|
" _argtys_ = [('x', C.float)]",
|
||||||
|
" ",
|
||||||
|
" def body(self, x):",
|
||||||
|
" libm = LibM(self) # init the API",
|
||||||
|
" y = libm.sqrtf(x) # call sqrtf",
|
||||||
|
" self.ret(y)",
|
||||||
|
" ",
|
||||||
|
"llvm_sqrtf = TestSqrtf()(m)",
|
||||||
|
"sqrtf = exe.get_ctype_function(llvm_sqrtf, 'float, float')",
|
||||||
|
"print(sqrtf(144))"
|
||||||
|
],
|
||||||
|
"language": "python",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"output_type": "stream",
|
||||||
|
"stream": "stdout",
|
||||||
|
"text": [
|
||||||
|
"12.0"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"prompt_number": 13
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"source": [
|
||||||
|
"Casting",
|
||||||
|
"-------",
|
||||||
|
"",
|
||||||
|
"Unlike C, llvm_cbuilder does not automatically cast variables.",
|
||||||
|
"It is up to the user to explicit cast types.",
|
||||||
|
"All binary operations require both operands to be the same type.",
|
||||||
|
"All values in llvm_cbuilder has a `cast(destty)` method.",
|
||||||
|
"",
|
||||||
|
"For example:"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"collapsed": true,
|
||||||
|
"input": [
|
||||||
|
"class CastExample(CDefinition):",
|
||||||
|
" _name_ = 'cast_example'",
|
||||||
|
" _retty_ = C.float",
|
||||||
|
" _argtys_ = [('x', C.int)]",
|
||||||
|
" ",
|
||||||
|
" def body(self, x):",
|
||||||
|
" y = x.cast(C.float) # cast integer x to float",
|
||||||
|
" self.ret(y)"
|
||||||
|
],
|
||||||
|
"language": "python",
|
||||||
|
"outputs": [],
|
||||||
|
"prompt_number": 14
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"source": [
|
||||||
|
"More... (TODO)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
BIN
notebook/llvm_cbuilder_intro.pdf
Normal file
BIN
notebook/llvm_cbuilder_intro.pdf
Normal file
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue