Closed adi-lb-phoenix closed 4 months ago
Can you write some C code and show generated LLVM IR with clang?
LLVM has many casting ops, we need to decide on which ones to implement: https://llvm.org/docs/LangRef.html#conversion-operations
My C code :
#include<stdio.h>
float int_to_float(int x){
float y ;
y = x ;
return y ;
}
int main(){
int a = 10;
printf("%f",int_to_float(a));
}
LLVM IR of the above code generated using : clang -S -emit-llvm <filename>
; ModuleID = 'I_2_F.c'
source_filename = "I_2_F.c"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
@.str = private unnamed_addr constant [3 x i8] c"%f\00", align 1
; Function Attrs: noinline nounwind optnone uwtable
define dso_local float @int_to_float(i32 noundef %0) #0 {
%2 = alloca i32, align 4
%3 = alloca float, align 4
store i32 %0, ptr %2, align 4
%4 = load i32, ptr %2, align 4
%5 = sitofp i32 %4 to float
store float %5, ptr %3, align 4
%6 = load float, ptr %3, align 4
ret float %6
}
; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @main() #0 {
%1 = alloca i32, align 4
store i32 10, ptr %1, align 4
%2 = load i32, ptr %1, align 4
%3 = call float @int_to_float(i32 noundef %2)
%4 = fpext float %3 to double
%5 = call i32 (ptr, ...) @printf(ptr noundef @.str, double noundef %4)
ret i32 0
}
declare i32 @printf(ptr noundef, ...) #1
attributes #0 = { noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #1 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
!llvm.module.flags = !{!0, !1, !2, !3, !4}
!llvm.ident = !{!5}
!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 8, !"PIC Level", i32 2}
!2 = !{i32 7, !"PIE Level", i32 2}
!3 = !{i32 7, !"uwtable", i32 2}
!4 = !{i32 7, !"frame-pointer", i32 2}
!5 = !{!"clang version 18.1.7"}
We should be able to do something similar to the below :
(define ((main void)) (declare a int) (declare b float) (declare c float) (set a 10) (set b 10.0) (declare a float) (set c (fadd a b)) (call fprint c)
I don't think this should be the syntax. Semantically, a
is redeclared so that it is used as a float instead of an int.
I think we should implement casting as an operator, like how C does it. So in this example, a
should not be modified, and the result of the casting expression will be a new floating-point value.
Explicit casts in C work like this:
int val;
val = 10; // val is integer 10
float fval;
fval = (float) val; // fval is float 10, and val is still integer 10
Following the same pattern in C-Lisp, we would end up with something like:
(declare val int)
(set val 10) ; val is integer 10
(declare fval float)
(set fval (sitofp val)) ; fval is float 10, and fval is still integer 10
sitofp
(or whatever name we decide on) would be the casting operator.
I agree with your point, we should not redeclare it, rather use it as a casting operator. Regarding naming conventions. I do not think it best to use any keywords that are implemented in any other language, as I believe it might lead to issues while debugging. Although C-lisp and llvm.py are apart by one compiler (brilisp.py).
(c-lisp
(define ((fprint float) (n float) )) (define ((main void)) (declare a int) (declare b float) (declare c float) (set a 10) (set b 10.0) (declare a float) (set c (fadd a b)) (call fprint c) )
)
The error occurred when it was passed to llvm.py
command : guile ../../utils/sexp-json.scm < test.sexp | python ../../c-lisp.py | python ../../brilisp.py | python ../../llvm.py
Output:
Exception: Operands must be the same type, got (i32, float); in instruction Munch({'op': 'fadd', 'type': 'float', 'dest': 'tmp_clisp-ftucgfgr', 'args': ['tmp_clisp.inp_0-bvlsnznb', 'tmp_clisp.inp_1-pgvljqyz']}):
Traceback (most recent call last):
File "/home/aadithya.bhat/c_lisp/bril/bril-txt/llama.lisp/src/backend/tests/c-lisp/../../llvm.py", line 359, in <module>
main()
File "/home/aadithya.bhat/c_lisp/bril/bril-txt/llama.lisp/src/backend/tests/c-lisp/../../llvm.py", line 354, in main
code_gen.generate(bril_prog)
File "/home/aadithya.bhat/c_lisp/bril/bril-txt/llama.lisp/src/backend/tests/c-lisp/../../llvm.py", line 44, in generate
self.gen_function(fn)
File "/home/aadithya.bhat/c_lisp/bril/bril-txt/llama.lisp/src/backend/tests/c-lisp/../../llvm.py", line 345, in gen_function
self.gen_instructions(fn_instrs)
File "/home/aadithya.bhat/c_lisp/bril/bril-txt/llama.lisp/src/backend/tests/c-lisp/../../llvm.py", line 261, in gen_instructions
raise e
File "/home/aadithya.bhat/c_lisp/bril/bril-txt/llama.lisp/src/backend/tests/c-lisp/../../llvm.py", line 252, in gen_instructions
gen_value(instr)
File "/home/aadithya.bhat/c_lisp/bril/bril-txt/llama.lisp/src/backend/tests/c-lisp/../../llvm.py", line 163, in gen_value
llvm_instr(*[self.gen_var(arg) for arg in instr.args], name=instr.dest),
File "/home/aadithya.bhat/.local/lib/python3.10/site-packages/llvmlite/ir/builder.py", line 34, in wrapped
raise ValueError("Operands must be the same type, got (%s, %s)"
ValueError: Operands must be the same type, got (i32, float)
So we need to make the change before we Exception: Operands must be the same type, got (i32, float); in instruction Munch({'op': 'fadd', 'type': 'float', 'dest': 'tmp_clisp-ftucgfgr', 'args': ['tmp_clisp.inp_0-bvlsnznb', 'tmp_clisp.inp_1-pgvljqyz']}):
.
So when this error is discovered . Can we look at the function return type ? Based on the function return type convert that data type for which the error was raised. Ex In this above case when the the variable was discovered to not be int. Could we do sitofp i32 'tmp_clisp.inp_0-bvlsnznb' to float
?
How did the function traversal happen :
main()
-> code_gen.generate(bril_prog)
-> self.gen_function(fn)
-> self.gen_instructions(fn_instrs)
-> self.gen_instructions(fn_instrs)
-> raise e
in gen_instructions
-> gen_value(instr) in gen_instructions
->
check the below line in the code : line 163, in gen_value llvm_instr(*[self.gen_var(arg) for arg in instr.args], name=instr.dest), File "home/.local/lib/python3.10/site-packages/llvmlite/ir/builder.py", line 34, in wrapped raise ValueError("Operands must be the same type, got (%s, %s)"
On inspecting gen_value
function. The error seems to be returning from llvm_instr(*[self.gen_var(arg) for arg in instr.args], name=instr.dest)
.
I printed the contents of the list fed into llvm_instr()
function.
print([self.gen_var(arg) for arg in instr.args] ,"REPL")
Contents :
[<ir.LoadInstr '.12' of type 'i32', opname 'load', operands [<ir.AllocaInstr 'tmp_clisp.inp_0-gjhylhwu' of type 'i32*', opname 'alloca', operands ()>]>, <ir.LoadInstr '.13' of type 'float', opname 'load', operands [<ir.AllocaInstr 'tmp_clisp.inp_1-ffnjzeqi' of type 'float*', opname 'alloca', operands ()>]>] REPL
REPL is just to recognize the printed contents
Above 3 comments are to be ignored for now.
` (c-lisp
(define ((fprint float) (n float) ))
(define ((main void))
(declare a int)
(declare b float)
(declare c float)
(set a 10)
(set b 10.0)
(declare a float)
(set c (fadd a b))
(call fprint c)
)
)Error in statement: ['declare', 'a', 'float']
Traceback (most recent call last):
File "/home/aadithya.bhat/c_lisp/bril/bril-txt/llama.lisp/src/backend/tests/c-lisp/llama2.c/int_to_float/../../../../c-lisp.py", line 473, in
(c-lisp
(define ((fprint float) (n float) ))
(define ((main void))
(declare a int)
(declare b float)
(declare c float)
(set a 10)
(set b 10.0)
(sitofp a)
(set c (fadd a b))
(call fprint c)
)
`
exp-json.scm < test.sexp | python ../../../../c-lisp.py
Error in statement: ['sitofp', 'a']
Traceback (most recent call last):
File "/home/aadithya.bhat/c_lisp/bril/bril-txt/llama.lisp/src/backend/tests/c-lisp/llama2.c/int_to_float/../../../../c-lisp.py", line 473, in
We will not try to solve this in C-lisp first, but we will do it from brilisp first.
(brilisp
(define ((print int) (n int)))
(define ((add5 float) (n int))
(set (five float) (const 5.0))
(sitofp n)
(set (sum float) (add n five))
(ret sum)
)
(define (( main float))
(set (a int) (const 9))
(set (b int) (call add5 a))
(set (tmp int)(call print b))
(ret b)
)
command executed : guile ../../../utils/sexp-json.scm < I_2_F.sexp | python ../../../brilisp_1.py
Output :
Traceback (most recent call last):
File "/home/aadithya.bhat/c_lisp/bril/bril-txt/llama.lisp/src/backend/tests/brilisp/int_to_float/../../../brilisp_1.py", line 174, in <module>
main()
File "/home/aadithya.bhat/c_lisp/bril/bril-txt/llama.lisp/src/backend/tests/brilisp/int_to_float/../../../brilisp_1.py", line 170, in main
print(json.dumps(brilisp(expr)))
File "/home/aadithya.bhat/c_lisp/bril/bril-txt/llama.lisp/src/backend/tests/brilisp/int_to_float/../../../brilisp_1.py", line 165, in brilisp
return {"functions": [gen_function(x) for x in body]}
File "/home/aadithya.bhat/c_lisp/bril/bril-txt/llama.lisp/src/backend/tests/brilisp/int_to_float/../../../brilisp_1.py", line 165, in <listcomp>
return {"functions": [gen_function(x) for x in body]}
File "/home/aadithya.bhat/c_lisp/bril/bril-txt/llama.lisp/src/backend/tests/brilisp/int_to_float/../../../brilisp_1.py", line 23, in gen_function
"instrs": [gen_instr(x) for x in instrs],
File "/home/aadithya.bhat/c_lisp/bril/bril-txt/llama.lisp/src/backend/tests/brilisp/int_to_float/../../../brilisp_1.py", line 23, in <listcomp>
"instrs": [gen_instr(x) for x in instrs],
File "/home/aadithya.bhat/c_lisp/bril/bril-txt/llama.lisp/src/backend/tests/brilisp/int_to_float/../../../brilisp_1.py", line 157, in gen_instr
raise SyntaxError(f"Unknown instruction {instr}")
SyntaxError: Unknown instruction ['sitofp', 'n']
Here is how I'd go about implementing cast in Brilisp:
sitofp
. In terms of the Brilisp compiler architecture, this will be defined alongside other operations like the arithmetic, pointer, etc.sitofp
takes the result type as an argument (the result is a floating-point, but the argument specifies precision -- float
/double
). For now, we will hardcode that argument since we have only one floating-point type.Some operations you can look at for reference:
id
: Possibly the simplest instruction.add
: Direct mapping to LLVM instructions.Defined the below functions in gen_instr(instr):
of brilisp_1.py. brilisp_1py is a copy of brilisp.py.
def is_sitofp(instr):
return instr[0] == "sitofp"
def gen_sitofp_instr(instr):
return {"op":"sitofp", "type":instr[1][1], "args": instr[1][0]}
def is_fptosi(instr):
return instr[0] == "fptosi"
def gen_fptosi_instr(instr):
return {"op":"fptosi", "type":instr[1][1], "args": instr[1][0]}
Why did I do it ? I observed that in this function, each instruction was being checked if the 0th position of that list matched a instruction name and if true a a new function in the name of "gen_instructionNAME_instr" was called to generate instructions for the matched instruction from one form to brilisp format. Next step is to observe th e functions calling functions such as the above and add conditions/statements in that calling function that lets the above defined functions be called to verify and generate instructions when instructions such as "sitofp" and "fitosi" is encountered.
@GlowingScrewdriver
Here is how I'd go about implementing cast in Brilisp:
* Create a new operator in Brilisp. Call it by the same name as LLVM's int-to-float cast: `sitofp`. In terms of the Brilisp compiler architecture, this will be defined alongside other operations like the arithmetic, pointer, etc. * LLVM `sitofp` takes the result type as an argument (the result is a floating-point, but the argument specifies precision -- `float`/`double`). For now, we will hardcode that argument since we have only one floating-point type. * Do not insert implicit casts anywhere. That is a conscious design decision adopted in both Brilisp and C-Lisp. If a cast is needed, the programmer will write one.
Some operations you can look at for reference:
* `id`: Possibly the simplest instruction. * Any "value" instruction, like `add`: Direct mapping to LLVM instructions.
I have taken your valuable suggestions and the directions into account 💯 👍
I have added the below lines of code :
elif is_sitofp(instr):
return gen_sitofp_instr(instr)
elif is_fptosi(instr):
return (gen_fptosi_instr)
along with these :
if is_const(instr):
return gen_constr_instr(instr)
elif is_value(instr):
return gen_value_instr(instr)
elif is_ret(instr):
return gen_ret_instr(instr)
elif is_call(instr):
return gen_call_instr(instr)
elif is_jmp(instr):
return gen_jmp_instr(instr)
elif is_label(instr):
return gen_label_instr(instr)
elif is_br(instr):
return gen_br_instr(instr)
elif is_nop(instr):
return gen_nop_instr(instr)
elif is_store(instr):
return gen_store_instr(instr)
elif is_sitofp(instr):
return gen_sitofp_instr(instr)
elif is_fptosi(instr):
return (gen_fptosi_instr)
else:
raise SyntaxError(f"Unknown instruction {instr}")
All the above code is present in gen_instr(instr)
function
Executed the below program
(brilisp
(define ((print int) (n int)))
(define ((add5 float) (n int))
(set (five float) (const 5.0))
(sitofp n)
(set (sum float) (add n five))
(ret sum)
)
(define (( main float))
(set (a int) (const 9))
(set (b float) (call add5 a))
(set (tmp int)(call print b))
(ret b)
)
Output when excuted command guile ../../../utils/sexp-json.scm < I_2_F.sexp | python ../../../brilisp_1.py
.
Output :
{"functions": [{"name": "print", "type": "int", "args": [{"name": "n", "type": "int"}], "instrs": []}, {"name": "add5", "type": "float", "args": [{"name": "n", "type": "int"}], "instrs": [{"op": "const", "type": "float", "dest": "five", "value": 5.0}, {"op": "sitofp", "args": "n"}, {"op": "add", "type": "float", "dest": "sum", "args": ["n", "five"]}, {"op": "ret", "args": ["sum"]}]}, {"name": "main", "type": "float", "args": [], "instrs": [{"op": "const", "type": "int", "dest": "a", "value": 9}, {"op": "call", "type": "float", "dest": "b", "funcs": ["add5"], "args": ["a"]}, {"op": "call", "type": "int", "dest": "tmp", "funcs": ["print"], "args": ["b"]}, {"op": "ret", "args": ["b"]}]}]}
We don't want to change the original variable while performing a cast. The cast operator takes an integer as an operand, and produces a new floating-point value. So add5
in your program should look something like:
(define ((add5 float) (n int))
(set (five float) (const 5.0))
(set (f_n float) (sitofp n))
(set (sum float) (add f_n five))
(ret sum)
)
Why don't you want to change the original variable ? is it To maintain scope ?
Because that's not how casts work in LLVM, (or C, for that matter). And we are saving ourselves much of the trouble of language design by adopting the semantics of LLVM and C.
Thing is, we can't think of all the caveats of a design decision when we make it. But the C language has been around for decades, and has undergone many improvements. LLVM too is quite mature. So following their footsteps definitely can't go wrong.
(brilisp
(define ((print int) (n int)))
(define ((add5 float) (n int))
(set (five float) (const 5.0))
(set (f_n float) (sitofp n))
(set (sum float) (add n five))
(ret sum)
)
(define (( main float))
(set (a int) (const 9))
(set (b float) (call add5 a))
(set (tmp int)(call print b))
(ret b)
)
)
In brilisp_1.py added sitofp
def is_value(instr):
value_op = {
"add",
"mul",
"sub",
"div",
"eq",
"ne",
"lt",
"gt",
"le",
"ge",
"not",
"and",
"or",
"alloc",
"load",
"ptradd",
"id",
"fadd",
"fsub",
"fmul",
"fdiv",
"feq",
"fne",
"flt",
"fgt",
"fle",
"fge",
"sitofp",
"fptosi"
}
made Changes to the function defined https://github.com/chsasank/llama.lisp/issues/67#issuecomment-2211671406 as below
def is_sitofp(instr):
print(instr,"REPL")
if instr[1][1] not in ["float"]:
raise TypeError("type does not match float")
return instr[0] == "sitofp"
def gen_sitofp_instr(instr):
return {"op":"sitofp","type":instr[1][1],"args": instr[1][0]}
def is_fptosi(instr):
print(instr,"REPL")
if instr[1][1] not in ["int"]:
raise TypeError("type does not match int")
return instr[0] == "fptosi"
def gen_fptosi_instr(instr):
return {"op":"fptosi", "type":instr[1][1], "args": instr[1][0]}
guile ../../../utils/sexp-json.scm < I_2_F.sexp | python ../../../brilisp_1.py
{"functions": [{"name": "print", "type": "int", "args": [{"name": "n", "type": "int"}], "instrs": []}, {"name": "add5", "type": "float", "args": [{"name": "n", "type": "int"}], "instrs": [{"op": "const", "type": "float", "dest": "five", "value": 5.0}, {"op": "sitofp", "type": "float", "dest": "f_n", "args": ["n"]}, {"op": "add", "type": "float", "dest": "sum", "args": ["n", "five"]}, {"op": "ret", "args": ["sum"]}]}, {"name": "main", "type": "float", "args": [], "instrs": [{"op": "const", "type": "int", "dest": "a", "value": 9}, {"op": "call", "type": "float", "dest": "b", "funcs": ["add5"], "args": ["a"]}, {"op": "call", "type": "int", "dest": "tmp", "funcs": ["print"], "args": ["b"]}, {"op": "ret", "args": ["b"]}]}]}
{"op": "sitofp", "type": "float", "dest": "f_n", "args": ["n"]} .
Next step will be to build IR for the sitofp
and fptosi
in gen_instructions function in llvm.py. The call to build IR from llvm.py will begin from
elif instr.op == "sitofp":
gen_sitofp(instr)
elif instr.op =="fptosi":
gen_fptosi(instr)
I will use this https://llvmlite.readthedocs.io/en/latest/user-guide/ir/ir-builder.html#llvmlite.ir.IRBuilder.sitofp to create IR for sitofp
in llvm.py , the function which will build the IR for sitofp :
def gen_sitofp(instr):
# IRBuilder.sitofp(value, typ, name='')
self.declare_var(self.gen_type(instr.type), instr.dest)
self.gen_symbol_store(instr.dest,
self.builder.sitofp(
self.gen_var(instr.args[0]),self.gen_type(instr.type),name=self.gen_var(instr.dest))
Command : guile ../../../utils/sexp-json.scm < I_2_F.sexp | python ../../../brilisp_1.py | python ../../../llvm.py
Output :
Traceback (most recent call last):
File "/home/aadithya.bhat/.local/lib/python3.10/site-packages/llvmlite/ir/_utils.py", line 46, in __str__
return self.__cached_str
AttributeError: 'CastInstr' object has no attribute '_StrCaching__cached_str'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/aadithya.bhat/.local/lib/python3.10/site-packages/llvmlite/ir/_utils.py", line 56, in get_reference
return self.__cached_refstr
AttributeError: 'CastInstr' object has no attribute '_StringReferenceCaching__cached_refstr'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/aadithya.bhat/c_lisp/bril/bril-txt/llama.lisp/src/backend/tests/brilisp/int_to_float/../../../llvm.py", line 379, in <module>
main()
File "/home/aadithya.bhat/c_lisp/bril/bril-txt/llama.lisp/src/backend/tests/brilisp/int_to_float/../../../llvm.py", line 375, in main
print(code_gen.module)
File "/home/aadithya.bhat/.local/lib/python3.10/site-packages/llvmlite/ir/module.py", line 242, in __repr__
lines += self._get_body_lines()
File "/home/aadithya.bhat/.local/lib/python3.10/site-packages/llvmlite/ir/module.py", line 212, in _get_body_lines
lines += [str(v) for v in self.globals.values()]
File "/home/aadithya.bhat/.local/lib/python3.10/site-packages/llvmlite/ir/module.py", line 212, in <listcomp>
lines += [str(v) for v in self.globals.values()]
File "/home/aadithya.bhat/.local/lib/python3.10/site-packages/llvmlite/ir/values.py", line 1015, in __str__
self.descr(buf)
File "/home/aadithya.bhat/.local/lib/python3.10/site-packages/llvmlite/ir/values.py", line 1010, in descr
self.descr_body(buf)
File "/home/aadithya.bhat/.local/lib/python3.10/site-packages/llvmlite/ir/values.py", line 1004, in descr_body
blk.descr(buf)
File "/home/aadithya.bhat/.local/lib/python3.10/site-packages/llvmlite/ir/values.py", line 1174, in descr
buf += [" {0}\n".format(instr) for instr in self.instructions]
File "/home/aadithya.bhat/.local/lib/python3.10/site-packages/llvmlite/ir/values.py", line 1174, in <listcomp>
buf += [" {0}\n".format(instr) for instr in self.instructions]
File "/home/aadithya.bhat/.local/lib/python3.10/site-packages/llvmlite/ir/_utils.py", line 48, in __str__
s = self.__cached_str = self._to_string()
File "/home/aadithya.bhat/.local/lib/python3.10/site-packages/llvmlite/ir/values.py", line 547, in _to_string
buf.append("{0} = ".format(self.get_reference()))
File "/home/aadithya.bhat/.local/lib/python3.10/site-packages/llvmlite/ir/_utils.py", line 58, in get_reference
s = self.__cached_refstr = self._get_reference()
File "/home/aadithya.bhat/.local/lib/python3.10/site-packages/llvmlite/ir/values.py", line 567, in _get_reference
if '\\' in name or '"' in name:
TypeError: argument of type 'LoadInstr' is not iterable
in llvm.py , the function which will build the IR for sitofp :
def gen_sitofp(instr): # IRBuilder.sitofp(value, typ, name='') self.declare_var(self.gen_type(instr.type), instr.dest) self.gen_symbol_store(instr.dest, self.builder.sitofp( self.gen_var(instr.args[0]),self.gen_type(instr.type),name=self.gen_var(instr.dest))
Command :
guile ../../../utils/sexp-json.scm < I_2_F.sexp | python ../../../brilisp_1.py | python ../../../llvm.py
Updated an instruction in
gen_sitofpfunction :
self.gen_var(instr.args[0]),self.gen_type(instr.type),name=instr.dest` Output :%".5" = load float, float* %"f_n" REPL ; ModuleID = "" target triple = "unknown-unknown-unknown" target datalayout = ""
declare float @"fprint"(float %".1")
define float @"add5"(i32 %"n") { alloca-bncsohpf: %"n.1" = alloca i32 %"five" = alloca float %"f_n" = alloca float %"sum" = alloca float br label %"entry-toewuyga" entry-toewuyga: store i32 %"n", i32 %"n.1" store float 0x4014000000000000, float %"five" %".5" = load float, float %"f_n" %".6" = load i32, i32 %"n.1" %"f_n.1" = sitofp i32 %".6" to float store float %"f_n.1", float %"f_n" %".8" = load float, float %"f_n" %".9" = load float, float %"five" %"sum.1" = fadd float %".8", %".9" store float %"sum.1", float %"sum" %".11" = load float, float* %"sum" ret float %".11" }
define float @"main"() { alloca-npgxravk: %"a" = alloca i32 %"b" = alloca float %"tmp" = alloca float br label %"entry-yuytbslm" entry-yuytbslm: store i32 9, i32 %"a" %".3" = load i32, i32 %"a" %"b.1" = call float @"add5"(i32 %".3") store float %"b.1", float %"b" %".5" = load float, float %"b" %"tmp.1" = call float @"fprint"(float %".5") store float %"tmp.1", float %"tmp" %".7" = load float, float %"b" ret float %".7" }
Brilisp file :
(brilisp
(define ((fprint float) (n float)))
(define ((add5 float) (n int))
(set (five float) (const 5.0))
(set (f_n float) (sitofp n))
(set (sum float) (fadd f_n five))
(ret sum)
)
(define (( main float))
(set (a int) (const 9))
(set (b float) (call add5 a))
(set (tmp float) (call fprint b))
(ret b)
)
)
Command :
guile ../../../utils/sexp-json.scm < I_2_F.sexp | python ../../../brilisp_1.py | python ../../../llvm.py | bash ../run.sh
Output :
14.000000
For float to int in brilisp.py we had already added the functions is_fptosi(instr)
and gen_fptosi_instr(instr)
which would verify and generate the required library for us.
in llvm.py
We add the below function in gen_instructions
def gen_fptosi(instr):
self.declare_var(self.gen_type(instr.type), instr.dest)
self.gen_symbol_store(instr.dest,
self.builder.fptosi(
self.gen_var(instr.args[0]),self.gen_type(instr.type),name=instr.dest
)
)
And the below lines of code
elif instr.op == "sitofp":
gen_sitofp(instr)
elif instr.op =="fptosi":
gen_fptosi(instr)
in gen_instructions(self, instrs):
The below brilisp code does conversion from float to int and performs addition operation on int and a value which has been converted from float to int.
(brilisp
(define ((print int) (n int)))
(define ((add5 int) (n float))
(set (five int) (const 5))
(set (f_n int) (fptosi n))
(set (sum int) (add f_n five))
(ret sum)
)
(define (( main int))
(set (a float) (const 9.0))
(set (b int) (call add5 a))
(set (tmp int) (call print b))
(ret b)
)
)
Command : guile ../../../utils/sexp-json.scm < F_2_I.sexp | python ../../../brilisp.py | python ../../../llvm.py | bash ../run.sh
Output :
14
Don't use this issue to post progress on the code. That's what you should use a PR for.
We should be able to cast floating point values from integer values . We do not have equivalent C code and its LLVM IR issue. for ex :
We cannot add 'a' and 'b' as both of them are in different formats. We should be able to change the format of 'a' to float before adding it.
We should be able to do something similar to the below :
The output when the above is executed executed :