[LLVMdev] Saving a reference to a Basic Block?

John Slagel john.slagel at gmail.com
Sat Nov 10 06:03:24 PST 2012


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)






















































More information about the llvm-dev mailing list