Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Requst arm backend. #160

Open
lygstate opened this issue Jan 7, 2021 · 17 comments
Open

Requst arm backend. #160

lygstate opened this issue Jan 7, 2021 · 17 comments

Comments

@lygstate
Copy link

lygstate commented Jan 7, 2021

As mir are so small, it's may suite for small soc, such as RPI2, RPI Zero and so on.

@vnmakarov
Copy link
Owner

The MIR design was mostly oriented to 64-bit targets as 32-bit market share is decreasing. Integer regs are 64-bit wide in MIR (although a program can use only 32-bits for each reg by using 32-bit MIR insns only).

But I kept in my mind possible usage of it for 32-bit targets too.

Currently porting MIR to 32-bit targets approximately requires the same efforts as for 64-bit targets. You just need to use 2 hard regs for one MIR reg. To generate more efficient code (using one hard reg for MIR integer reg involved only in 32-bit insns), an additional analysis should be implemented in MIR-generator to say machine-dependent generator code that one hard register can be used for given MIR integer reg.

@RussellHaley
Copy link

Hi Vladimir,

I see someone else has asked a similar question to the one I posted on your blog. I have no business playing here but I am fascinated by MIR.

I was able to generate a.bmir from your seive code. I can run it using ./c2m <filename> -ei | [eg|el], I didn't see a command line app for just running mir binaries (e.g. a.bmir)? I will assume that the instructions in the main README are how one would put that together to create a little C "VM"? seive-interp.c seems to point the way.

@RussellHaley
Copy link

Okay, well I've set up a little project over here: https://github.com/RussellHaley/mircVM
I don't know how to link my files to system libraries yet:

osboxes@osboxes ~/g/m/b/l/x/release (master)> ls
b2ctab*  b2m*  c2m*  cvm*  libmir.a  m2b*  run-test.lua*  sieve.mir
osboxes@osboxes ~/g/m/b/l/x/release (master)> cat sieve.mir
M0:	module
proto0:	proto	i32, u64:U0___format, ...
proto1:	proto	i32, i32:i0_N
proto2:	proto	
	import	printf
sieve:	func	i32, i32:i0_N
	local	i64:fp, i64:I0_n, i64:I_0, i64:i_1, i64:I0_count, i64:I0_i, i64:i_2, i64:I_3
	local	i64:I_4, i64:i_5, i64:i_6, i64:I0_prime, i64:I_7, i64:I_8, i64:I0_k, i64:I_9
	local	i64:i_10, i64:I_11, i64:I_12, i64:I_13, i64:i_14, i64:I_15, i64:I_16, i64:i_17
	local	i64:I_18, i64:I_19, i64:i_20
# 1 arg, 27 locals
	alloca	fp, 819008
	mov	I0_n, 0
	ext32	I_0, i0_N
	bge	L3, I0_n, I_0
L1:
	mov	I0_count, 0
	mov	I0_i, 0
	bge	L6, I0_i, 819000
L4:
	ext8	I_3, 1
	mov	i8:(fp, I0_i), I_3
L5:
	mov	I_4, I0_i
	add	I_4, I_4, 1
	mov	I0_i, I_4
	blt	L4, I0_i, 819000
L6:
	mov	I0_i, 0
	bge	L9, I0_i, 819000
L7:
	bf	L11, i8:(fp, I0_i)
L10:
	add	I_7, I0_i, I0_i
	add	I_8, I_7, 3
	mov	I0_prime, I_8
	add	I_9, I0_i, I0_prime
	mov	I0_k, I_9
	bge	L15, I0_k, 819000
L13:
	ext8	I_11, 0
	mov	i8:(fp, I0_k), I_11
L14:
	mov	I_12, I0_k
	add	I_12, I_12, I0_prime
	mov	I0_k, I_12
	blt	L13, I0_k, 819000
L15:
	mov	I_15, I0_count
	add	I_15, I_15, 1
	mov	I0_count, I_15
	jmp	L12
L11:
L12:
L8:
	mov	I_16, I0_i
	add	I_16, I_16, 1
	mov	I0_i, I_16
	blt	L7, I0_i, 819000
L9:
L2:
	mov	I_18, I0_n
	add	I_18, I_18, 1
	mov	I0_n, I_18
	ext32	I_19, i0_N
	blt	L1, I0_n, I_19
L3:
	ret	I0_count
	endfunc
	export	sieve
ex100:	func	
	local	i64:i_0, i64:i_1
# 0 args, 2 locals
	call	proto1, sieve, i_1, 100
	call	proto0, printf, i_0, "sieve (100) = %d\000", i_1
	ret
	endfunc
	export	ex100
main:	func	i32, i32:i0_argc, u64:U0_argv

# 2 args, 0 locals
	call	proto2, ex100
	ret	0
	endfunc
	export	main
	endmodule
osboxes@osboxes ~/g/m/b/l/x/release (master)> ./cvm sieve.mir
import of undefined item printf

cvm main.c:

#include <stdio.h>
#include "mir.h"
#include "readfile.h"

int interp(char *str)
{
	MIR_module_t m;
	MIR_item_t func;

	MIR_context_t ctx = MIR_init ();

	size_t len = strlen (str);
	MIR_scan_string (ctx, str);
	m = DLIST_TAIL (MIR_module_t, *MIR_get_module_list (ctx));

	MIR_load_module (ctx, m);

	MIR_link (ctx, MIR_set_interp_interface, NULL);

	MIR_val_t val;
	MIR_interp (ctx, func, &val, 0);

	MIR_finish (ctx);

	return 0;
}

int main(int argc, char** argv)
{
	char *str;
	if(argc > 1)
	{
		if(readfile(argv[1], &str) == 0)
		{
			//~ printf("not cool %s", str);
			interp(str);
		}
	}
	else
	{
		printf("Need to pass a filename\n");
		return 1;
	}
	
	if(str != NULL) free(str);

	printf("That's all folks.\n");
	return 0;
}

@RussellHaley
Copy link

Ah, okay I see now about loading externals. I'm running into this error now:

cvm: mir/mir-interp.c:1609: interp_arr_varg: Assertion `func_item->item_type == MIR_func_item' failed.

Which I've figured out is telling me my "func" variable isn't pointing to the right entry point (e.g. an item_type of 2)?

osboxes@osboxes ~/g/m/b/l/x/release (master)> ./run-test.lua
File: /home/osboxes/git/mircVM//files/C/sieve.c
/home/osboxes/git/mircVM/build/linux/x86_64/release
enum val 3
name -1818507584
cvm: mir/mir-interp.c:1609: interp_arr_varg: Assertion `func_item->item_type == MIR_func_item' failed.
Aborted (core dumped)
#include <stdio.h>
#include "mir.h"
#include "readfile.h"

int interp(char *str)
{
	int retval = 0;
	MIR_module_t m;
	MIR_item_t func;

	MIR_context_t ctx = MIR_init ();

	size_t len = strlen (str);
	MIR_scan_string (ctx, str);
	m = DLIST_TAIL (MIR_module_t, *MIR_get_module_list (ctx));
	if(m == NULL)
	{
		printf("Failed to get the module items\n");
		retval = 2;
	}
	else
	{
		func = DLIST_TAIL (MIR_item_t, m->items); 
		if(func == NULL)
		{
			printf("WTH?");
		}
		else
		{
			printf("enum val %d\n", func->item_type);
			printf("name %d\n", func->module->name);
		}
		MIR_load_module (ctx, m);
		MIR_load_external (ctx, "printf", printf);
		MIR_link (ctx, MIR_set_interp_interface, NULL);

		MIR_val_t val;
		MIR_interp (ctx, func, &val, 0);
	}
	MIR_finish (ctx);

	return retval;
}

int main(int argc, char** argv)
{
	char *str;
	if(argc > 1)
	{
		if(readfile(argv[1], &str) == 0)
		{
			//~ printf("not cool %s", str);
			interp(str);
		}
	}
	else
	{
		printf("Need to pass a filename\n");
		return 1;
	}
	
	if(str != NULL) free(str);

	printf("That's all folks.\n");
	return 0;
}

@RussellHaley
Copy link

RussellHaley commented Feb 7, 2021

Okay, finally got something working!

#include <stdio.h>
//~ #include "mir-dlist.h"
#include "mir.h"
#include "readfile.h"


char *strings[] = {"func", "proto", "import", "export", "forward", "data", "ref_data", "expr_data"};

int interp(char *str)
{
	int retval = 0;
	MIR_module_t m;
	MIR_item_t entry_point = NULL;

	MIR_context_t ctx = MIR_init ();

	size_t len = strlen (str);
	MIR_scan_string (ctx, str);
	m = DLIST_TAIL (MIR_module_t, *MIR_get_module_list (ctx));
	if(m == NULL)
	{
		printf("Failed to get the module items\n");
		retval = 2;
	}
	else
	{
		int len = DLIST_LENGTH(MIR_item_t, m->items);
		MIR_item_t element;
		for(int i=0; i<len; i++)
		{
			element = DLIST_EL(MIR_item_t, m->items, i);
			printf("enum val %d\n", element->item_type);
			printf("type %s\n", strings[element->item_type]);
			printf("module %s\n", element->module->name);
			if( element->item_type == 0 )
			{
			 	printf("name %s\n", element->u.func->name);
			 	if(strncmp("main", element->u.func->name, 4) ==0)
			 	{
					entry_point = element;
					break;
				}
			}
			printf("----------------\n");
		}
		
		if(entry_point != NULL)
		{
			MIR_load_external (ctx, "printf", printf);
			MIR_load_module (ctx, m);
			
			
			MIR_link (ctx, MIR_set_interp_interface, NULL);
			
			typedef int64_t (*loop_func) (void);
			MIR_set_interp_interface (ctx, entry_point);
			int64_t res = ((loop_func) entry_point->addr) ();
		}
		//~ MIR_val_t val;
		//~ MIR_interp (ctx, func, &val, 0);
	}
	MIR_finish (ctx);

	return retval;
}

int main(int argc, char** argv)
{
	char *str;
	if(argc > 1)
	{
		if(readfile(argv[1], &str) == 0)
		{
			//~ printf("not cool %s", str);
			interp(str);
		}
	}
	else
	{
		printf("Need to pass a filename\n");
		return 1;
	}
	
	if(str != NULL) free(str);

	printf("That's all folks.\n");
	return 0;
}
osboxes@osboxes ~/g/m/b/l/x/release (master)> ./run-test.lua
File: /home/osboxes/git/mircVM//files/C/sieve.c
/home/osboxes/git/mircVM/build/linux/x86_64/release
enum val 1
type proto
module M0
----------------
enum val 1
type proto
module M0
----------------
enum val 1
type proto
module M0
----------------
enum val 2
type import
module M0
----------------
enum val 0
type func
module M0
name sieve
----------------
enum val 3
type export
module M0
----------------
enum val 0
type func
module M0
name ex100
----------------
enum val 3
type export
module M0
----------------
enum val 0
type func
module M0
name main
sieve (100) = 123814That's all folks.

I assume there is a better way to do this? I also assume I mutilated your rather spiffy DLIST. (I'll search for some examples in the code)

@lygstate
Copy link
Author

lygstate commented Feb 7, 2021

wonderfull work:)

@RussellHaley
Copy link

Bit rot is real. My arm boards seem to spontaneously combust. I'm re-imaging a Hummingboard with a dual core NXP iMX6 (probably won't finish in time tonight). I also have an old beaglebone to test on.

I have copied the Aarch64 files as Aarch32. Wikipedia says Aarch32 is the official term now. I do know that the "arm" moniker is the historic one. Thoughts @vnmakarov? FreeBSD was stuck referring to ArmV7 as ArmV6 for forever.

As I am not an expert, my plan was to attempt to build on a 32 bit arm platform and see what explodes. I see that there are hard coded register values that will need to be examined. I am hoping this step down between Aarch64 and armv7/armv8a will inform me as to what I might need to step down to the arm M4F (specifically I'm aiming at an Stm32MF466).

@rofl0r
Copy link

rofl0r commented Feb 8, 2021

afaik aarch32 is the ILP32 ABI for aarch64, same as x32 for x86_64. so it does use 64 bit registers for speed, but long and pointers are 32bit unlike on real 64 bit binaries.

@vnmakarov
Copy link
Owner

Thank you for trying MIR.

I didn't see a command line app for just running mir binaries (e.g. a.bmir)

You can run it with c2m: c2m a.bmir -eg. There is also utility b2ctab which translates MIR code into C code (containing a big C array representing encoded MIR). By linking the generated C code with MIR library, you can create a standalone executable. This executable will actually read MIR code from the C array, generate machine code, and execute it.

It is an experimental utility. I am planning to move its functionality into c2m.

Still MIR and c2m is not for everyday C programmer. It is hard to develop C code with c2m (e.g. absence of debugging support) Currently It is mostly for developers of JITs.

@vnmakarov
Copy link
Owner

afaik aarch32 is the ILP32 ABI for aarch64, same as x32 for x86_64. so it does use 64 bit registers for speed, but long and pointers are 32bit unlike on real 64 bit binaries.

HJ Lu from Intel designed x32 and implemented it in GCC. FIrst it was promising but at the end it never flys. Now I guess it is a burden. I guess the same might happen with arm ilp32. Smaller code is important especially in container environments but few percent (or 10-20%) is not a big difference.

But 100 times difference in code size of LLVM/GCC based JIT and MIR JIT compiler has some sense.

@RussellHaley
Copy link

afaik aarch32 is the ILP32 ABI for aarch64, same as x32 for x86_64. so it does use 64 bit registers for speed, but long and pointers are 32bit unlike on real 64 bit binaries.

I see. So it would not be an appropriate name. Thanks for clarifying.

@RussellHaley
Copy link

Thank you for trying MIR.

I didn't see a command line app for just running mir binaries (e.g. a.bmir)

You can run it with c2m: c2m a.bmir -eg. There is also utility b2ctab which translates MIR code into C code (containing a big C array representing encoded MIR). By linking the generated C code with MIR library, you can create a standalone executable. This executable will actually read MIR code from the C array, generate machine code, and execute it.

It is an experimental utility. I am planning to move its functionality into c2m.

Thank you for clarifying. I did manage to figure out the tools a little after reading through the documents a few more times (and I did figure out the b2ctab.

Still MIR and c2m is not for everyday C programmer. It is hard to develop C code with c2m (e.g. absence of debugging support) Currently It is mostly for developers of JITs.

Yes, I realize. But it sure is fun riding on your coat tails! The thought is just for prototyping a 32 bit port and gaining familiarity.

@RussellHaley
Copy link

Hello! Well I finally have an arm board working. @vnmakarov, your genius has even managed to foil my incompetence and I managed build and run/fail c2m on my beaglebone:

debian@beaglebone:~/git/mircVM/build/linux/armv7a/release$ ls
b2ctab  b2m  c2m  cvm  libmir.a  m2b  run-test.lua  sieve.mir
debian@beaglebone:~/git/mircVM/build/linux/armv7a/release$ lua run-test.lua
File: /home/debian/git/mircVM//files/C/sieve.c
pwd; ./c2m -S -o sieve.mir /home/debian/git/mircVM//files/C/sieve.c; ./cvm sieve.mir
/home/debian/git/mircVM/build/linux/armv7a/release
<environment>:55:9: standard macro __has_include redefinition
<environment>:11:9: warning -- different macro redefinition of __STDC_VERSION__
stdint.h:44:9: warning -- different macro redefinition of __INT64_C
stdint.h:45:9: warning -- different macro redefinition of __UINT64_C
/usr/include/stdio.h:27:10: error in opening file bits/libc-header-start.h
Failed to get the module items
That's all folks.

Pull request for comments is here: #162

@RussellHaley
Copy link

debian@beaglebone:~/cmake-3.19.4$ cmake --version
cmake version 3.19.4

CMake suite maintained and supported by Kitware (kitware.com/cmake).
debian@beaglebone:~/cmake-3.19.4$ uname -a
Linux beaglebone 4.19.94-ti-r42 #1buster SMP PREEMPT Tue Mar 31 19:38:29 UTC 2020 armv7l GNU/Linux

Lolz. That was way more difficult then it should have been, I finally just built from git. Thankfully the OS image from beaglebone comes pre-installed with build-essential. Hurray for sanity!

@vnmakarov, any chance I can convince you to switch to a sublime build system called xmake? Xmake installs everywhere and builds "everything". It's written in C/LuaJIT2 and it doesn't have the pitfalls of a meta build system like CMake. https://xmake.io/#/getting_started --> Check out the "Build as fast as ninja stats".

@lygstate
Copy link
Author

debian@beaglebone:~/cmake-3.19.4$ cmake --version
cmake version 3.19.4

CMake suite maintained and supported by Kitware (kitware.com/cmake).
debian@beaglebone:~/cmake-3.19.4$ uname -a
Linux beaglebone 4.19.94-ti-r42 #1buster SMP PREEMPT Tue Mar 31 19:38:29 UTC 2020 armv7l GNU/Linux

Lolz. That was way more difficult then it should have been, I finally just built from git. Thankfully the OS image from beaglebone comes pre-installed with build-essential. Hurray for sanity!

@vnmakarov, any chance I can convince you to switch to a sublime build system called xmake? Xmake installs everywhere and builds "everything". It's written in C/LuaJIT2 and it doesn't have the pitfalls of a meta build system like CMake. https://xmake.io/#/getting_started --> Check out the "Build as fast as ninja stats".

I suggest not to do that, CMake have broader usage even though have so much pitfalls, and many IDE support CMake.

@vnmakarov
Copy link
Owner

Pull request for comments is here: #162

Thank you for your work on arm32 port. It is a start. As I understand now with this patches we can generate MIR code from C on arm32. To make interpreter and generator working a lot of things still should be done.

I'll review your pull request. It might take couple weeks or more (I need to learn arm32 C ABI for this and honestly I am busy with other projects until mid-April).

@vnmakarov, any chance I can convince you to switch to a sublime build system called xmake? Xmake installs everywhere and builds "everything". It's written in C/LuaJIT2 and it doesn't have the pitfalls of a meta build system like CMake. https://xmake.io/#/getting_started --> Check out the "Build as fast as ninja stats".

Sorry, no. CMake is also non-standard feature for MIR project (it was initially added by logzero for Windows port). MIR project can live without this. Currently I use make even when working on Windows. I guess it will stay this way. I don't see any advantages to use anything besides widely used make right now. One my goal is to keep minimum dependencies. That is why I don't use yacc/lex or any external libraries.

@RussellHaley
Copy link

Pull request for comments is here: #162

Thank you for your work on arm32 port. It is a start. As I understand now with this patches we can generate MIR code from C on arm32. To make interpreter and generator working a lot of things still should be done.

No, it doesn't create anything yet. I will continue to hack away at this.

I'll review your pull request. It might take couple weeks or more (I need to learn arm32 C ABI for this and honestly I am busy with other projects until mid-April).

Is this the correct document to learn the arm32 C ABI? https://static.docs.arm.com/ihi0039/c/IHI0039C_clibabi.pdf

I'm happy to play by myself if you could give me a hint as to where to drill into the VM code? To be honest, I want to know how a VM works; I could go buy an RPi4 if I really wanted to. I am elated about the readability of the code and want to take advantage of this situation. It's not everyday one finds C code of this caliber that is easily accessible.

@vnmakarov, any chance I can convince you to switch to a sublime build system called xmake? Xmake installs everywhere and builds "everything". It's written in C/LuaJIT2 and it doesn't have the pitfalls of a meta build system like CMake. https://xmake.io/#/getting_started --> Check out the "Build as fast as ninja stats".

Sorry, no. CMake is also non-standard feature for MIR project (it was initially added by logzero for Windows port). MIR project can live without this. Currently I use make even when working on Windows. I guess it will stay this way. I don't see any advantages to use anything besides widely used make right now. One my goal is to keep minimum dependencies. That is why I don't use yacc/lex or any external libraries.

You're a gentleman for even commenting on the idea. Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants