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:
(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
basicblock2: ext_runtime_function_push(102): br sub2 ← 102 could be anything, the compiler stores a map of 102-to-basicblock2_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
Which works just fine. But what would be nice would be:
basicblock1: ext_func_push(handleof(basicblock1_ret) ): br sub1
basicblock2: ext_func_push(handleof(basicblock2_ret)): br sub2
basicblock.sub1: br basicblock.ret
basicblock.sub2: br basicblock.ret
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.
my-llvm-example.txt (6.01 KB)