Is there a way to save a reference to a Basic Block that gets all fixed up
in the linker, so that you can branch to it during execution? (Or maybe
just a better way to do what I'm trying to do?)
In my old-school BASIC compiler that I'm writing with LLVM, for each GOSUB,
I keep a map of an integer ID and a pointer to the basic block following
the GOSUB to return to.
Then, when a BASIC RETURN is executed, it pops the integer ID off a
software stack and executes a switch statement based on that ID to branch
to the Base Block to return to for that integer ID.
(I attached a text file with the input file, output file, and generated
LLVM code, if you want to see all the details).
But to explain it in psudeo code:
The BASIC code is:
gosub sub1
gosub sub2
sub1:
sub2:
return
(Note the "subroutine" has multiple entry points, or put another way,
the
subroutines can share common code or return statements)
Which translates to this llvm psuedo code:
basicblock1: ext_runtime_function_push(101): br sub1 <-- 101 could be
anything, the compiler stores a map of 101-to-basicblock1_ret
basicblock1_ret:
basicblock2: ext_runtime_function_push(102): br sub2 <-- 102 could be
anything, the compiler stores a map of 102-to-basicblock2_ret
basicblock2_ret:
br somewhere
basicblock.sub1: ...
basicblock.sub2: ...
br basicblock.ret
basicblock.ret:
switch( ext_runtime_func_pop() )
case 101: br basicblock1_ret <-- generated from the compiler's map of
101-to-basicblock1_ret
case 102: br basicblock2_ret <-- generated from the compiler's map of
102-to-basicblock2_ret
default: error
Which works just fine. But what would be nice would be:
basicblock1: ext_func_push(handleof(basicblock1_ret) ): br sub1
basicblock1_ret:
basicblock2: ext_func_push(handleof(basicblock2_ret)): br sub2
basicblock2_ret:
br somewhere
basicblock.sub1: br basicblock.ret
basicblock.sub2: br basicblock.ret
basicblock.ret:
br ext_func_pop()
Where, in the generated & linked Intel 386 assembly, its obvious that the
ext_func_push could push the 32-bit address of the basicblock1_ret label,
and the br would jump to that address. But how to get there from here?
Since I have a working solution, this is just a "shouldn't there be a
more
elegant way to do this?" question.
Thanks!!!
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
<http://lists.llvm.org/pipermail/llvm-dev/attachments/20121110/d8e9a315/attachment.html>
-------------- next part --------------
/////// THE BASIC CODE
defint a-z
print "Hello"
x$ = "a"
gosub sub1
x$ = "b"
gosub sub2
goto end.prog
sub1:
print "sub1=";x$
sub2:
print "sub2=";x$
return
end.prog:
print "Bye!"
////// WHICH GENERATES THIS OUTPUT
Hello
sub1=a
sub2=a
sub2=b
Bye!
////// THE GENERATED LLVM CODE
; ModuleID = 'jas1.bas'
%StrDesc = type <{ i16, i16, i8* }>
@"x$" = common global %StrDesc zeroinitializer, align 8
@GosubRet = common global i32 0, align 4
@0 = private unnamed_addr constant [6 x i8] c"Hello\00"
@1 = private unnamed_addr constant [2 x i8] c"a\00"
@2 = private unnamed_addr constant [2 x i8] c"b\00"
@3 = private unnamed_addr constant [6 x i8] c"sub1=\00"
@4 = private unnamed_addr constant [6 x i8] c"sub2=\00"
@5 = private unnamed_addr constant [5 x i8] c"Bye!\00"
define i32 @main() {
entrypoint:
%call_cfunc_data_init = call i32 @cfunc_data_init(i8* null, i32 0)
%call_func_str_tmpc = call %StrDesc* @cfunc_str_tmpc(i8* getelementptr inbound
s ([6 x i8]* @0, i32 0, i32 0), i32 5)
%0 = call i32 @cfunc_print_str(%StrDesc* %call_func_str_tmpc)
%call_str_tmp_free = call i32 @cfunc_str_tmp_free(%StrDesc* %call_func_str_tmp
c)
%1 = call i32 @cfunc_print_special(i32 1, i32 0)
%call_func_str_tmpc1 = call %StrDesc* @cfunc_str_tmpc(i8* getelementptr inboun
ds ([2 x i8]* @1, i32 0, i32 0), i32 1)
%call_str_sets = call i32 @cfunc_str_sets(%StrDesc* @"x$", %StrDesc*
%call_fun
c_str_tmpc1)
%call_str_tmp_free2 = call i32 @cfunc_str_tmp_free(%StrDesc* %call_func_str_tm
pc1)
%call_cfunc_push_retid = call i32 @cfunc_push_retid(i32 100)
br label %forward_ref_sub1
forward_ref_end.prog: ; preds = %post_gosub_block6
br label %end.prog
forward_ref_sub1: ; preds = %entrypoint
br label %sub1
forward_ref_sub2: ; preds = %post_gosub_block
br label %sub2
return_block: ; preds = %sub2
%call_cfunc_pop_retid = call i32 @cfunc_pop_retid()
switch i32 %call_cfunc_pop_retid, label %return_block_def [
i32 100, label %post_gosub_block
i32 101, label %post_gosub_block6
]
return_block_def: ; preds = %return_block
ret i32 0
post_gosub_block: ; preds = %return_block
%call_func_str_tmpc3 = call %StrDesc* @cfunc_str_tmpc(i8* getelementptr inboun
ds ([2 x i8]* @2, i32 0, i32 0), i32 1)
%call_str_sets4 = call i32 @cfunc_str_sets(%StrDesc* @"x$",
%StrDesc* %call_fu
nc_str_tmpc3)
%call_str_tmp_free5 = call i32 @cfunc_str_tmp_free(%StrDesc* %call_func_str_tm
pc3)
%call_cfunc_push_retid7 = call i32 @cfunc_push_retid(i32 101)
br label %forward_ref_sub2
post_gosub_block6: ; preds = %return_block
br label %forward_ref_end.prog
post_goto_block: ; No predecessors!
br label %sub1
sub1: ; preds = %forward_ref_sub1, %
post_goto_block
%call_func_str_tmpc8 = call %StrDesc* @cfunc_str_tmpc(i8* getelementptr inboun
ds ([6 x i8]* @3, i32 0, i32 0), i32 5)
%2 = call i32 @cfunc_print_str(%StrDesc* %call_func_str_tmpc8)
%call_str_tmp_free9 = call i32 @cfunc_str_tmp_free(%StrDesc* %call_func_str_tm
pc8)
%3 = call i32 @cfunc_print_str(%StrDesc* @"x$")
%4 = call i32 @cfunc_print_special(i32 1, i32 0)
br label %sub2
sub2: ; preds = %forward_ref_sub2, %
sub1
%call_func_str_tmpc10 = call %StrDesc* @cfunc_str_tmpc(i8* getelementptr inbou
nds ([6 x i8]* @4, i32 0, i32 0), i32 5)
%5 = call i32 @cfunc_print_str(%StrDesc* %call_func_str_tmpc10)
%call_str_tmp_free11 = call i32 @cfunc_str_tmp_free(%StrDesc* %call_func_str_t
mpc10)
%6 = call i32 @cfunc_print_str(%StrDesc* @"x$")
%7 = call i32 @cfunc_print_special(i32 1, i32 0)
br label %return_block
post_return_block: ; No predecessors!
br label %end.prog
end.prog: ; preds = %forward_ref_end.pro
g, %post_return_block
%call_func_str_tmpc12 = call %StrDesc* @cfunc_str_tmpc(i8* getelementptr inbou
nds ([5 x i8]* @5, i32 0, i32 0), i32 4)
%8 = call i32 @cfunc_print_str(%StrDesc* %call_func_str_tmpc12)
%call_str_tmp_free13 = call i32 @cfunc_str_tmp_free(%StrDesc* %call_func_str_t
mpc12)
%9 = call i32 @cfunc_print_special(i32 1, i32 0)
ret i32 0
}
declare i32 @cfunc_print_str(%StrDesc*)
declare i32 @cfunc_print_int(i32)
declare i32 @cfunc_print_float(float)
declare i32 @cfunc_print_double(double)
declare i32 @cfunc_print_special(i32, i32)
declare i32 @cfunc_data_init(i8*, i32)
declare i32 @cfunc_data_restore(i32)
declare i32 @cfunc_data_read_int()
declare i32 @cfunc_data_read_str(%StrDesc*)
declare i32 @cfunc_push_retid(i32)
declare i32 @cfunc_pop_retid()
declare i32 @cfunc_locate(i32, i32, i32, i32, i32)
declare i32 @cfunc_cls()
declare i32 @cfunc_end()
declare %StrDesc* @cfunc_inkey()
declare i32 @cfunc_val(%StrDesc*, i32*, float*)
declare double @cfunc_vald(%StrDesc*)
declare float @cfunc_valf(%StrDesc*)
declare %StrDesc* @cfunc_str(double)
declare i32 @cfunc_str_sets(%StrDesc*, %StrDesc*)
declare i32 @cfunc_str_lset(%StrDesc*, %StrDesc*)
declare i32 @cfunc_str_rset(%StrDesc*, %StrDesc*)
declare i32 @cfunc_str_compare(%StrDesc*, %StrDesc*)
declare %StrDesc* @cfunc_str_tmp_concat(%StrDesc*, %StrDesc*)
declare %StrDesc* @cfunc_str_tmpc(i8*, i32)
declare i32 @cfunc_str_tmp_free(%StrDesc*)
declare i32 @cfunc_line_input(%StrDesc*)
declare i32 @cfunc_input(%StrDesc*, i8*, i32)
declare i32 @cfunc_open(%StrDesc*, i32, i32, i32)
declare i32 @cfunc_close(i32)
declare i32 @cfunc_field_add(i32, i32, %StrDesc*)
declare i32 @cfunc_get(i32, i32)
declare i32 @cfunc_put(i32, i32)
declare i32 @cfunc_eof(i32)
declare i32 @cfunc_lof(i32)