native: support more arithmetic, int/string arrays, function returns and internal_strlen (#10279)
							parent
							
								
									04e77419cc
								
							
						
					
					
						commit
						012f866619
					
				| 
						 | 
					@ -280,11 +280,12 @@ jobs:
 | 
				
			||||||
          UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 ./v2 -o v.c cmd/v
 | 
					          UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 ./v2 -o v.c cmd/v
 | 
				
			||||||
      - name: Build V using V
 | 
					      - name: Build V using V
 | 
				
			||||||
        run: ./v -o v2 cmd/v && ./v2 -o v3 cmd/v
 | 
					        run: ./v -o v2 cmd/v && ./v2 -o v3 cmd/v
 | 
				
			||||||
      - name: v self compilation with -usecache
 | 
					# QTODO
 | 
				
			||||||
        run: |
 | 
					#      - name: v self compilation with -usecache
 | 
				
			||||||
          ./v -o v2 -usecache cmd/v
 | 
					#        run: |
 | 
				
			||||||
          ./v2 -o v3 -usecache cmd/v
 | 
					#          ./v -o v2 -usecache cmd/v
 | 
				
			||||||
          ./v3 -usecache examples/tetris/tetris.v
 | 
					#          ./v2 -o v3 -usecache cmd/v
 | 
				
			||||||
 | 
					#          ./v3 -usecache examples/tetris/tetris.v
 | 
				
			||||||
      - name: Test symlink
 | 
					      - name: Test symlink
 | 
				
			||||||
        run: ./v symlink
 | 
					        run: ./v symlink
 | 
				
			||||||
      #    - name: Set up pg database
 | 
					      #    - name: Set up pg database
 | 
				
			||||||
| 
						 | 
					@ -371,11 +372,12 @@ jobs:
 | 
				
			||||||
        run: ./v -freestanding run vlib/os/bare/bare_example_linux.v
 | 
					        run: ./v -freestanding run vlib/os/bare/bare_example_linux.v
 | 
				
			||||||
      - name: v self compilation
 | 
					      - name: v self compilation
 | 
				
			||||||
        run: ./v -o v2 cmd/v && ./v2 -o v3 cmd/v && ./v3 -o v4 cmd/v
 | 
					        run: ./v -o v2 cmd/v && ./v2 -o v3 cmd/v && ./v3 -o v4 cmd/v
 | 
				
			||||||
      - name: v self compilation with -usecache
 | 
					# QTODO
 | 
				
			||||||
        run: |
 | 
					#      - name: v self compilation with -usecache
 | 
				
			||||||
          ./v -o v2 -usecache cmd/v
 | 
					#        run: |
 | 
				
			||||||
          ./v2 -o v3 -usecache cmd/v
 | 
					#          ./v -o v2 -usecache cmd/v
 | 
				
			||||||
          ./v3 -usecache examples/tetris/tetris.v
 | 
					#          ./v2 -o v3 -usecache cmd/v
 | 
				
			||||||
 | 
					#          ./v3 -usecache examples/tetris/tetris.v
 | 
				
			||||||
      - name: Verify `v test` works
 | 
					      - name: Verify `v test` works
 | 
				
			||||||
        run: |
 | 
					        run: |
 | 
				
			||||||
          ./v cmd/tools/test_if_v_test_system_works.v
 | 
					          ./v cmd/tools/test_if_v_test_system_works.v
 | 
				
			||||||
| 
						 | 
					@ -460,11 +462,12 @@ jobs:
 | 
				
			||||||
          ASAN_OPTIONS=detect_leaks=0 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 ./v5 -o v.c cmd/v
 | 
					          ASAN_OPTIONS=detect_leaks=0 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 ./v5 -o v.c cmd/v
 | 
				
			||||||
      - name: v self compilation
 | 
					      - name: v self compilation
 | 
				
			||||||
        run: ./v -o v2 cmd/v && ./v2 -o v3 cmd/v && ./v3 -o v4 cmd/v
 | 
					        run: ./v -o v2 cmd/v && ./v2 -o v3 cmd/v && ./v3 -o v4 cmd/v
 | 
				
			||||||
      - name: v self compilation with -usecache
 | 
					# QTODO
 | 
				
			||||||
        run: |
 | 
					#      - name: v self compilation with -usecache
 | 
				
			||||||
          ./v -o v2 -usecache cmd/v
 | 
					#        run: |
 | 
				
			||||||
          ./v2 -o v3 -usecache cmd/v
 | 
					#          ./v -o v2 -usecache cmd/v
 | 
				
			||||||
          ./v3 -usecache examples/tetris/tetris.v
 | 
					#          ./v2 -o v3 -usecache cmd/v
 | 
				
			||||||
 | 
					#          ./v3 -usecache examples/tetris/tetris.v
 | 
				
			||||||
      - name: Verify `v test` works
 | 
					      - name: Verify `v test` works
 | 
				
			||||||
        run: |
 | 
					        run: |
 | 
				
			||||||
          ./v cmd/tools/test_if_v_test_system_works.v
 | 
					          ./v cmd/tools/test_if_v_test_system_works.v
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,7 +9,6 @@ mut:
 | 
				
			||||||
	// arm64 specific stuff for code generation
 | 
						// arm64 specific stuff for code generation
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// string_addr map[string]i64
 | 
					 | 
				
			||||||
// The registers are ordered for faster generation
 | 
					// The registers are ordered for faster generation
 | 
				
			||||||
// push rax => 50
 | 
					// push rax => 50
 | 
				
			||||||
// push rcx => 51 etc
 | 
					// push rcx => 51 etc
 | 
				
			||||||
| 
						 | 
					@ -39,9 +38,23 @@ const (
 | 
				
			||||||
	fn_arg_registers = [Register.rdi, .rsi, .rdx, .rcx, .r8, .r9]
 | 
						fn_arg_registers = [Register.rdi, .rsi, .rdx, .rcx, .r8, .r9]
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn (mut g Gen) dec(reg Register) {
 | 
				
			||||||
 | 
						g.write16(0xff48)
 | 
				
			||||||
 | 
						match reg {
 | 
				
			||||||
 | 
							.rax { g.write8(0xc8) }
 | 
				
			||||||
 | 
							.rbx { g.write8(0xcb) }
 | 
				
			||||||
 | 
							.rcx { g.write8(0xc9) }
 | 
				
			||||||
 | 
							.rsi { g.write8(0xce) }
 | 
				
			||||||
 | 
							.rdi { g.write8(0xcf) }
 | 
				
			||||||
 | 
							.r12 { g.write8(0xc4) }
 | 
				
			||||||
 | 
							else { panic('unhandled inc $reg') }
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn (mut g Gen) inc(reg Register) {
 | 
					fn (mut g Gen) inc(reg Register) {
 | 
				
			||||||
	g.write16(0xff49)
 | 
						g.write16(0xff49)
 | 
				
			||||||
	match reg {
 | 
						match reg {
 | 
				
			||||||
 | 
							.rcx { g.write8(0xc1) }
 | 
				
			||||||
		.r12 { g.write8(0xc4) }
 | 
							.r12 { g.write8(0xc4) }
 | 
				
			||||||
		else { panic('unhandled inc $reg') }
 | 
							else { panic('unhandled inc $reg') }
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -149,20 +162,40 @@ fn (mut g Gen) jmp(addr i64) {
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
fn (mut g Gen) mov64(reg Register, val i64) {
 | 
					fn (mut g Gen) mov64(reg Register, val i64) {
 | 
				
			||||||
	match reg {
 | 
						match reg {
 | 
				
			||||||
 | 
							.rax {
 | 
				
			||||||
 | 
								g.write8(0x48)
 | 
				
			||||||
 | 
								g.write8(0xb8)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							.rcx {
 | 
				
			||||||
 | 
								g.write8(0x48)
 | 
				
			||||||
 | 
								g.write8(0xc7)
 | 
				
			||||||
 | 
								g.write8(0xc1)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							.rbx {
 | 
				
			||||||
 | 
								g.write8(0x48)
 | 
				
			||||||
 | 
								g.write8(0xc7)
 | 
				
			||||||
 | 
								g.write8(0xc3)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		.rsi {
 | 
							.rsi {
 | 
				
			||||||
			g.write8(0x48)
 | 
								g.write8(0x48)
 | 
				
			||||||
			g.write8(0xbe)
 | 
								g.write8(0xbe)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		else {
 | 
							else {
 | 
				
			||||||
			eprintln('unhandled mov $reg')
 | 
								eprintln('unhandled mov64 $reg')
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	g.write64(val)
 | 
						g.write64(val)
 | 
				
			||||||
	g.println('mov64 $reg, $val')
 | 
						g.println('mov64 $reg, $val')
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn (mut g Gen) mov_reg_to_rbp(var_offset int, reg Register) {
 | 
					fn (mut g Gen) mov_reg_to_var(var_offset int, reg Register) {
 | 
				
			||||||
	// 89 7d fc     mov DWORD PTR [rbp-0x4],edi
 | 
						// 89 7d fc     mov DWORD PTR [rbp-0x4],edi
 | 
				
			||||||
 | 
						match reg {
 | 
				
			||||||
 | 
							.rax, .rsi {
 | 
				
			||||||
 | 
								g.write8(0x48)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else {}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	g.write8(0x89)
 | 
						g.write8(0x89)
 | 
				
			||||||
	match reg {
 | 
						match reg {
 | 
				
			||||||
		.eax, .rax { g.write8(0x45) }
 | 
							.eax, .rax { g.write8(0x45) }
 | 
				
			||||||
| 
						 | 
					@ -178,12 +211,19 @@ fn (mut g Gen) mov_reg_to_rbp(var_offset int, reg Register) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn (mut g Gen) mov_var_to_reg(reg Register, var_offset int) {
 | 
					fn (mut g Gen) mov_var_to_reg(reg Register, var_offset int) {
 | 
				
			||||||
	// 8b 7d f8          mov edi,DWORD PTR [rbp-0x8]
 | 
						// 8b 7d f8          mov edi,DWORD PTR [rbp-0x8]
 | 
				
			||||||
 | 
						match reg {
 | 
				
			||||||
 | 
							.rax, .rsi {
 | 
				
			||||||
 | 
								g.write8(0x48)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else {}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	g.write8(0x8b)
 | 
						g.write8(0x8b)
 | 
				
			||||||
	match reg {
 | 
						match reg {
 | 
				
			||||||
		.eax, .rax { g.write8(0x45) }
 | 
							.eax, .rax { g.write8(0x45) }
 | 
				
			||||||
		.edi, .rdi { g.write8(0x7d) }
 | 
							.edi, .rdi { g.write8(0x7d) }
 | 
				
			||||||
		.rsi { g.write8(0x75) }
 | 
							.rsi { g.write8(0x75) }
 | 
				
			||||||
		.rdx { g.write8(0x55) }
 | 
							.rdx { g.write8(0x55) }
 | 
				
			||||||
 | 
							.rbx { g.write8(0x5d) }
 | 
				
			||||||
		.rcx { g.write8(0x4d) }
 | 
							.rcx { g.write8(0x4d) }
 | 
				
			||||||
		else { verror('mov_var_to_reg $reg') }
 | 
							else { verror('mov_var_to_reg $reg') }
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -257,7 +297,7 @@ pub fn (mut g Gen) sub8(reg Register, val int) {
 | 
				
			||||||
	g.println('sub8 $reg,$val.hex2()')
 | 
						g.println('sub8 $reg,$val.hex2()')
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn (mut g Gen) add(reg Register, val int) {
 | 
					pub fn (mut g Gen) sub(reg Register, val int) {
 | 
				
			||||||
	g.write8(0x48)
 | 
						g.write8(0x48)
 | 
				
			||||||
	g.write8(0x81)
 | 
						g.write8(0x81)
 | 
				
			||||||
	g.write8(0xe8 + int(reg)) // TODO rax is different?
 | 
						g.write8(0xe8 + int(reg)) // TODO rax is different?
 | 
				
			||||||
| 
						 | 
					@ -265,6 +305,16 @@ pub fn (mut g Gen) add(reg Register, val int) {
 | 
				
			||||||
	g.println('add $reg,$val.hex2()')
 | 
						g.println('add $reg,$val.hex2()')
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn (mut g Gen) add(reg Register, val int) {
 | 
				
			||||||
 | 
						if reg != .rax {
 | 
				
			||||||
 | 
							panic('add only works with .rax')
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						g.write8(0x48)
 | 
				
			||||||
 | 
						g.write8(0x05)
 | 
				
			||||||
 | 
						g.write32(val)
 | 
				
			||||||
 | 
						g.println('add $reg,$val.hex2()')
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn (mut g Gen) add8(reg Register, val int) {
 | 
					pub fn (mut g Gen) add8(reg Register, val int) {
 | 
				
			||||||
	g.write8(0x48)
 | 
						g.write8(0x48)
 | 
				
			||||||
	g.write8(0x83)
 | 
						g.write8(0x83)
 | 
				
			||||||
| 
						 | 
					@ -294,6 +344,16 @@ fn (mut g Gen) sub8_var(reg Register, var_offset int) {
 | 
				
			||||||
	g.println('sub8 $reg,DWORD PTR[rbp-$var_offset.hex2()]')
 | 
						g.println('sub8 $reg,DWORD PTR[rbp-$var_offset.hex2()]')
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn (mut g Gen) div8_var(reg Register, var_offset int) {
 | 
				
			||||||
 | 
						if reg == .rax || reg == .eax {
 | 
				
			||||||
 | 
							g.mov_var_to_reg(.rbx, var_offset)
 | 
				
			||||||
 | 
							g.div_reg(.rax, .rbx)
 | 
				
			||||||
 | 
							g.mov_reg_to_var(var_offset, .rax)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							panic('div8_var invalid source register')
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn (mut g Gen) mul8_var(reg Register, var_offset int) {
 | 
					fn (mut g Gen) mul8_var(reg Register, var_offset int) {
 | 
				
			||||||
	g.write8(0x0f)
 | 
						g.write8(0x0f)
 | 
				
			||||||
	g.write8(0xaf)
 | 
						g.write8(0xaf)
 | 
				
			||||||
| 
						 | 
					@ -327,17 +387,75 @@ pub fn (mut g Gen) save_main_fn_addr() {
 | 
				
			||||||
	g.main_fn_addr = i64(g.buf.len)
 | 
						g.main_fn_addr = i64(g.buf.len)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn (mut g Gen) allocate_string(s string, opsize int) int {
 | 
				
			||||||
 | 
						g.strings << s
 | 
				
			||||||
 | 
						str_pos := g.buf.len + opsize
 | 
				
			||||||
 | 
						g.str_pos << str_pos
 | 
				
			||||||
 | 
						return 0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn (mut g Gen) cld_repne_scasb() {
 | 
				
			||||||
 | 
						g.write8(0xfc)
 | 
				
			||||||
 | 
						g.println('cld')
 | 
				
			||||||
 | 
						g.write8(0xf2)
 | 
				
			||||||
 | 
						g.write8(0xae)
 | 
				
			||||||
 | 
						g.println('repne scasb')
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn (mut g Gen) xor(r Register, v int) {
 | 
				
			||||||
 | 
						if v == -1 {
 | 
				
			||||||
 | 
							match r {
 | 
				
			||||||
 | 
								.rcx {
 | 
				
			||||||
 | 
									g.write8(0x48)
 | 
				
			||||||
 | 
									g.write8(0x83)
 | 
				
			||||||
 | 
									g.write8(0xf1)
 | 
				
			||||||
 | 
									g.write8(0xff)
 | 
				
			||||||
 | 
									g.println('xor rcx, -1')
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else {
 | 
				
			||||||
 | 
									verror('unhandled xor')
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							verror('unhandled xor')
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// return length in .rax of string pointed by given register
 | 
				
			||||||
 | 
					pub fn (mut g Gen) inline_strlen(r Register) {
 | 
				
			||||||
 | 
						g.mov_reg(.rdi, r)
 | 
				
			||||||
 | 
						g.mov(.rcx, -1)
 | 
				
			||||||
 | 
						g.mov(.eax, 0)
 | 
				
			||||||
 | 
						g.cld_repne_scasb()
 | 
				
			||||||
 | 
						g.xor(.rcx, -1)
 | 
				
			||||||
 | 
						g.dec(.rcx)
 | 
				
			||||||
 | 
						g.mov_reg(.rax, .rcx)
 | 
				
			||||||
 | 
						g.println('strlen rax, $r')
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO: strlen of string at runtime
 | 
				
			||||||
 | 
					pub fn (mut g Gen) gen_print_reg(r Register, n int) {
 | 
				
			||||||
 | 
						mystrlen := true
 | 
				
			||||||
 | 
						g.mov_reg(.rsi, r)
 | 
				
			||||||
 | 
						if mystrlen {
 | 
				
			||||||
 | 
							g.inline_strlen(.rsi)
 | 
				
			||||||
 | 
							g.mov_reg(.rdx, .rax)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							g.mov(.edx, n)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						g.mov(.eax, g.nsyscall_write())
 | 
				
			||||||
 | 
						g.mov(.edi, 1)
 | 
				
			||||||
 | 
						g.syscall()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn (mut g Gen) gen_print(s string) {
 | 
					pub fn (mut g Gen) gen_print(s string) {
 | 
				
			||||||
	//
 | 
						//
 | 
				
			||||||
	// qq := s + '\n'
 | 
						// qq := s + '\n'
 | 
				
			||||||
	//
 | 
						//
 | 
				
			||||||
	g.strings << s
 | 
					 | 
				
			||||||
	// g.string_addr[s] = str_pos
 | 
					 | 
				
			||||||
	g.mov(.eax, g.nsyscall_write())
 | 
						g.mov(.eax, g.nsyscall_write())
 | 
				
			||||||
	g.mov(.edi, 1)
 | 
						g.mov(.edi, 1)
 | 
				
			||||||
	str_pos := g.buf.len + 2
 | 
						// segment_start +  0x9f) // str pos // placeholder
 | 
				
			||||||
	g.str_pos << str_pos
 | 
						g.mov64(.rsi, g.allocate_string(s, 2)) // for rsi its 2
 | 
				
			||||||
	g.mov64(.rsi, 0) // segment_start +  0x9f) // str pos // placeholder
 | 
					 | 
				
			||||||
	g.mov(.edx, s.len) // len
 | 
						g.mov(.edx, s.len) // len
 | 
				
			||||||
	g.syscall()
 | 
						g.syscall()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -399,6 +517,27 @@ pub fn (mut g Gen) gen_amd64_exit(expr ast.Expr) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn (mut g Gen) mov(reg Register, val int) {
 | 
					fn (mut g Gen) mov(reg Register, val int) {
 | 
				
			||||||
 | 
						if val == -1 {
 | 
				
			||||||
 | 
							match reg {
 | 
				
			||||||
 | 
								.rax {
 | 
				
			||||||
 | 
									g.write8(0x48)
 | 
				
			||||||
 | 
									g.write8(0xc7)
 | 
				
			||||||
 | 
									g.write8(0xc0)
 | 
				
			||||||
 | 
									g.write32(-1)
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								.rcx {
 | 
				
			||||||
 | 
									g.write8(0x48)
 | 
				
			||||||
 | 
									g.write8(0xc7)
 | 
				
			||||||
 | 
									g.write8(0xc1)
 | 
				
			||||||
 | 
									g.write32(-1)
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else {
 | 
				
			||||||
 | 
									verror('unhandled mov $reg, -1')
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if val == 0 {
 | 
						if val == 0 {
 | 
				
			||||||
		// Optimise to xor reg, reg when val is 0
 | 
							// Optimise to xor reg, reg when val is 0
 | 
				
			||||||
		match reg {
 | 
							match reg {
 | 
				
			||||||
| 
						 | 
					@ -410,6 +549,16 @@ fn (mut g Gen) mov(reg Register, val int) {
 | 
				
			||||||
				g.write8(0x31)
 | 
									g.write8(0x31)
 | 
				
			||||||
				g.write8(0xff)
 | 
									g.write8(0xff)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								.rcx {
 | 
				
			||||||
 | 
									g.write8(0x48)
 | 
				
			||||||
 | 
									g.write8(0x31)
 | 
				
			||||||
 | 
									g.write8(0xc7)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								.rdx {
 | 
				
			||||||
 | 
									g.write8(0x48)
 | 
				
			||||||
 | 
									g.write8(0x31)
 | 
				
			||||||
 | 
									g.write8(0xd2)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			.edx {
 | 
								.edx {
 | 
				
			||||||
				g.write8(0x31)
 | 
									g.write8(0x31)
 | 
				
			||||||
				g.write8(0xd2)
 | 
									g.write8(0xd2)
 | 
				
			||||||
| 
						 | 
					@ -425,7 +574,7 @@ fn (mut g Gen) mov(reg Register, val int) {
 | 
				
			||||||
				g.write8(0xe4)
 | 
									g.write8(0xe4)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			else {
 | 
								else {
 | 
				
			||||||
				panic('unhandled mov $reg')
 | 
									verror('unhandled mov $reg, $reg')
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		g.println('xor $reg, $reg')
 | 
							g.println('xor $reg, $reg')
 | 
				
			||||||
| 
						 | 
					@ -437,6 +586,9 @@ fn (mut g Gen) mov(reg Register, val int) {
 | 
				
			||||||
			.edi, .rdi {
 | 
								.edi, .rdi {
 | 
				
			||||||
				g.write8(0xbf)
 | 
									g.write8(0xbf)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								.rcx {
 | 
				
			||||||
 | 
									g.write8(0xc7)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			.edx {
 | 
								.edx {
 | 
				
			||||||
				g.write8(0xba)
 | 
									g.write8(0xba)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					@ -457,13 +609,97 @@ fn (mut g Gen) mov(reg Register, val int) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn (mut g Gen) mov_reg(a Register, b Register) {
 | 
					fn (mut g Gen) mul_reg(a Register, b Register) {
 | 
				
			||||||
	match a {
 | 
						if a != .rax {
 | 
				
			||||||
		.rbp {
 | 
							panic('mul always operates on rax')
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						match b {
 | 
				
			||||||
 | 
							.rax {
 | 
				
			||||||
			g.write8(0x48)
 | 
								g.write8(0x48)
 | 
				
			||||||
			g.write8(0x89)
 | 
								g.write8(0xf7)
 | 
				
			||||||
 | 
								g.write8(0xe8)
 | 
				
			||||||
 | 
								g.println('mul $a')
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		else {}
 | 
							.rbx {
 | 
				
			||||||
 | 
								g.write8(0x48)
 | 
				
			||||||
 | 
								g.write8(0xf7)
 | 
				
			||||||
 | 
								g.write8(0xeb)
 | 
				
			||||||
 | 
								g.println('mul $a')
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else {
 | 
				
			||||||
 | 
								panic('unhandled div $a')
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn (mut g Gen) div_reg(a Register, b Register) {
 | 
				
			||||||
 | 
						if a != .rax {
 | 
				
			||||||
 | 
							panic('div always operates on rax')
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						match b {
 | 
				
			||||||
 | 
							.rax {
 | 
				
			||||||
 | 
								g.write8(0x48)
 | 
				
			||||||
 | 
								g.write8(0xf7)
 | 
				
			||||||
 | 
								g.write8(0xf8)
 | 
				
			||||||
 | 
								g.println('div $a')
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							.rbx {
 | 
				
			||||||
 | 
								g.mov(.edx, 0)
 | 
				
			||||||
 | 
								g.write8(0x48)
 | 
				
			||||||
 | 
								g.write8(0xf7)
 | 
				
			||||||
 | 
								g.write8(0xfb) // idiv ebx
 | 
				
			||||||
 | 
								g.println('div $a')
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else {
 | 
				
			||||||
 | 
								panic('unhandled div $a')
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn (mut g Gen) sub_reg(a Register, b Register) {
 | 
				
			||||||
 | 
						if a == .rax && b == .rbx {
 | 
				
			||||||
 | 
							g.write8(0x48)
 | 
				
			||||||
 | 
							g.write8(0x29)
 | 
				
			||||||
 | 
							g.write8(0xd8)
 | 
				
			||||||
 | 
							g.println('sub $a, $b')
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							panic('unhandled add $a, $b')
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn (mut g Gen) add_reg(a Register, b Register) {
 | 
				
			||||||
 | 
						if a == .rax && b == .rbx {
 | 
				
			||||||
 | 
							g.write8(0x48)
 | 
				
			||||||
 | 
							g.write8(0x01)
 | 
				
			||||||
 | 
							g.write8(0xd8)
 | 
				
			||||||
 | 
							g.println('add $a, $b')
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							panic('unhandled add $a, $b')
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn (mut g Gen) mov_reg(a Register, b Register) {
 | 
				
			||||||
 | 
						if a == .rbp && b == .rsp {
 | 
				
			||||||
 | 
							g.write8(0x48)
 | 
				
			||||||
 | 
							g.write8(0x89)
 | 
				
			||||||
 | 
						} else if a == .rdx && b == .rax {
 | 
				
			||||||
 | 
							g.write8(0x48)
 | 
				
			||||||
 | 
							g.write8(0x89)
 | 
				
			||||||
 | 
							g.write8(0xc2)
 | 
				
			||||||
 | 
						} else if a == .rax && b == .rcx {
 | 
				
			||||||
 | 
							g.write8(0x48)
 | 
				
			||||||
 | 
							g.write8(0x89)
 | 
				
			||||||
 | 
							g.write8(0xc8)
 | 
				
			||||||
 | 
						} else if a == .rdi && b == .rsi {
 | 
				
			||||||
 | 
							g.write8(0x48)
 | 
				
			||||||
 | 
							g.write8(0x89)
 | 
				
			||||||
 | 
							g.write8(0xf7)
 | 
				
			||||||
 | 
						} else if a == .rsi && b == .rax {
 | 
				
			||||||
 | 
							g.write8(0x48)
 | 
				
			||||||
 | 
							g.write8(0x89)
 | 
				
			||||||
 | 
							g.write8(0xc6)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							verror('unhandled mov_reg combination for $a $b')
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -472,7 +708,7 @@ fn (mut g Gen) mov_rbp_rsp() {
 | 
				
			||||||
	g.write8(0x48)
 | 
						g.write8(0x48)
 | 
				
			||||||
	g.write8(0x89)
 | 
						g.write8(0x89)
 | 
				
			||||||
	g.write8(0xe5)
 | 
						g.write8(0xe5)
 | 
				
			||||||
	g.println('mov rbp,rsp')
 | 
						g.println('mov rbp, rsp')
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn (mut g Gen) call_fn(node ast.CallExpr) {
 | 
					pub fn (mut g Gen) call_fn(node ast.CallExpr) {
 | 
				
			||||||
| 
						 | 
					@ -481,8 +717,12 @@ pub fn (mut g Gen) call_fn(node ast.CallExpr) {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	name := node.name
 | 
						name := node.name
 | 
				
			||||||
	// println('call fn $name')
 | 
						mut n := name
 | 
				
			||||||
	addr := g.fn_addr[name]
 | 
						if !n.contains('.') {
 | 
				
			||||||
 | 
							n = 'main.$n'
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						println('call fn ($n)')
 | 
				
			||||||
 | 
						addr := g.fn_addr[n]
 | 
				
			||||||
	if addr == 0 {
 | 
						if addr == 0 {
 | 
				
			||||||
		verror('fn addr of `$name` = 0')
 | 
							verror('fn addr of `$name` = 0')
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -526,17 +766,117 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
 | 
				
			||||||
		// ident := left as ast.Ident
 | 
							// ident := left as ast.Ident
 | 
				
			||||||
		match right {
 | 
							match right {
 | 
				
			||||||
			ast.IntegerLiteral {
 | 
								ast.IntegerLiteral {
 | 
				
			||||||
				g.allocate_var(name, 4, right.val.int())
 | 
									// g.allocate_var(name, 4, right.val.int())
 | 
				
			||||||
 | 
									match node.op {
 | 
				
			||||||
 | 
										.plus_assign {
 | 
				
			||||||
 | 
											dest := g.get_var_offset(name)
 | 
				
			||||||
 | 
											g.mov_var_to_reg(.rax, dest)
 | 
				
			||||||
 | 
											g.add(.rax, right.val.int())
 | 
				
			||||||
 | 
											g.mov_reg_to_var(dest, .rax)
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										.minus_assign {
 | 
				
			||||||
 | 
											dest := g.get_var_offset(name)
 | 
				
			||||||
 | 
											g.mov_var_to_reg(.rax, dest)
 | 
				
			||||||
 | 
											g.mov_var_to_reg(.rbx, g.get_var_offset(name))
 | 
				
			||||||
 | 
											g.sub_reg(.rax, .rbx)
 | 
				
			||||||
 | 
											g.mov_reg_to_var(dest, .rax)
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										.mult_assign {
 | 
				
			||||||
 | 
											dest := g.get_var_offset(name)
 | 
				
			||||||
 | 
											g.mov_var_to_reg(.rax, dest)
 | 
				
			||||||
 | 
											g.mov_var_to_reg(.rbx, g.get_var_offset(name))
 | 
				
			||||||
 | 
											g.mul_reg(.rax, .rbx)
 | 
				
			||||||
 | 
											g.mov_reg_to_var(dest, .rax)
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										.div_assign {
 | 
				
			||||||
 | 
											dest := g.get_var_offset(name)
 | 
				
			||||||
 | 
											g.mov_var_to_reg(.rax, dest)
 | 
				
			||||||
 | 
											g.mov_var_to_reg(.rbx, g.get_var_offset(name))
 | 
				
			||||||
 | 
											g.div_reg(.rax, .rbx)
 | 
				
			||||||
 | 
											g.mov_reg_to_var(dest, .rax)
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										.decl_assign {
 | 
				
			||||||
 | 
											g.allocate_var(name, 4, right.val.int())
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										.assign {
 | 
				
			||||||
 | 
											match node.left_types[i] {
 | 
				
			||||||
 | 
												7 { // ast.IndexExpr {
 | 
				
			||||||
 | 
													ie := node.left[i] as ast.IndexExpr
 | 
				
			||||||
 | 
													bracket := name.index('[') or {
 | 
				
			||||||
 | 
														verror('bracket expected')
 | 
				
			||||||
 | 
														exit(1)
 | 
				
			||||||
 | 
													}
 | 
				
			||||||
 | 
													var_name := name[0..bracket]
 | 
				
			||||||
 | 
													mut dest := g.get_var_offset(var_name)
 | 
				
			||||||
 | 
													index := ie.index as ast.IntegerLiteral
 | 
				
			||||||
 | 
													dest += index.val.int() * 8
 | 
				
			||||||
 | 
													// TODO check if out of bounds access
 | 
				
			||||||
 | 
													g.mov(.rax, right.val.int())
 | 
				
			||||||
 | 
													g.mov_reg_to_var(dest, .rax)
 | 
				
			||||||
 | 
													// eprintln('${var_name}[$index] = ${right.val.int()}')
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
												else {
 | 
				
			||||||
 | 
													tn := node.left[i].type_name()
 | 
				
			||||||
 | 
													dump(node.left_types)
 | 
				
			||||||
 | 
													verror('unhandled assign type: $tn')
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										else {
 | 
				
			||||||
 | 
											eprintln('ERROR 2')
 | 
				
			||||||
 | 
											dump(node)
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			ast.InfixExpr {
 | 
								ast.InfixExpr {
 | 
				
			||||||
 | 
									// eprintln('infix') dump(node) dump(right)
 | 
				
			||||||
				g.infix_expr(right)
 | 
									g.infix_expr(right)
 | 
				
			||||||
				g.allocate_var(name, 4, 0)
 | 
									offset := g.allocate_var(name, 4, 0)
 | 
				
			||||||
				// `mov DWORD PTR [rbp-0x8],eax`
 | 
									// `mov DWORD PTR [rbp-0x8],eax`
 | 
				
			||||||
				offset := g.get_var_offset(name)
 | 
					 | 
				
			||||||
				if g.pref.is_verbose {
 | 
									if g.pref.is_verbose {
 | 
				
			||||||
					println('infix assignment $name offset=$offset.hex2()')
 | 
										println('infix assignment $name offset=$offset.hex2()')
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				g.mov_reg_to_rbp(offset, .eax)
 | 
									g.mov_reg_to_var(offset, .eax)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								ast.Ident {
 | 
				
			||||||
 | 
									// eprintln('identr') dump(node) dump(right)
 | 
				
			||||||
 | 
									match node.op {
 | 
				
			||||||
 | 
										.plus_assign {
 | 
				
			||||||
 | 
											dest := g.get_var_offset(name)
 | 
				
			||||||
 | 
											g.mov_var_to_reg(.rax, dest)
 | 
				
			||||||
 | 
											g.add8_var(.rax, g.get_var_offset(right.name))
 | 
				
			||||||
 | 
											g.mov_reg_to_var(dest, .rax)
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										.minus_assign {
 | 
				
			||||||
 | 
											dest := g.get_var_offset(name)
 | 
				
			||||||
 | 
											g.mov_var_to_reg(.rax, dest)
 | 
				
			||||||
 | 
											g.mov_var_to_reg(.rbx, g.get_var_offset(right.name))
 | 
				
			||||||
 | 
											g.sub_reg(.rax, .rbx)
 | 
				
			||||||
 | 
											g.mov_reg_to_var(dest, .rax)
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										.div_assign {
 | 
				
			||||||
 | 
											// this should be called when `a /= b` but it's not :?
 | 
				
			||||||
 | 
											dest := g.get_var_offset(name)
 | 
				
			||||||
 | 
											g.mov_var_to_reg(.rax, dest)
 | 
				
			||||||
 | 
											g.mov_var_to_reg(.rbx, g.get_var_offset(right.name))
 | 
				
			||||||
 | 
											g.div_reg(.rax, .rbx)
 | 
				
			||||||
 | 
											g.mov_reg_to_var(dest, .rax)
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										.decl_assign {
 | 
				
			||||||
 | 
											dest := g.allocate_var(name, 4, 0)
 | 
				
			||||||
 | 
											g.mov_var_to_reg(.rax, g.get_var_offset(right.name))
 | 
				
			||||||
 | 
											g.mov_reg_to_var(dest, .rax)
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										.assign {
 | 
				
			||||||
 | 
											g.mov_var_to_reg(.rax, g.get_var_offset(right.name))
 | 
				
			||||||
 | 
											g.mov_reg_to_var(g.get_var_offset(name), .rax)
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										else {
 | 
				
			||||||
 | 
											eprintln('TODO: unhandled assign ident case')
 | 
				
			||||||
 | 
											dump(node)
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									// a += b
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			ast.StructInit {
 | 
								ast.StructInit {
 | 
				
			||||||
				sym := g.table.get_type_symbol(right.typ)
 | 
									sym := g.table.get_type_symbol(right.typ)
 | 
				
			||||||
| 
						 | 
					@ -549,7 +889,58 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
 | 
				
			||||||
					g.allocate_var(field_name, 4, 0)
 | 
										g.allocate_var(field_name, 4, 0)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								ast.ArrayInit {
 | 
				
			||||||
 | 
									// check if array is empty
 | 
				
			||||||
 | 
									mut pos := g.allocate_array(name, 8, right.exprs.len)
 | 
				
			||||||
 | 
									// allocate array of right.exprs.len vars
 | 
				
			||||||
 | 
									for e in right.exprs {
 | 
				
			||||||
 | 
										match e {
 | 
				
			||||||
 | 
											ast.IntegerLiteral {
 | 
				
			||||||
 | 
												g.mov(.rax, e.val.int())
 | 
				
			||||||
 | 
												g.mov_reg_to_var(pos, .rax)
 | 
				
			||||||
 | 
												pos += 8
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
											ast.StringLiteral {
 | 
				
			||||||
 | 
												g.mov64(.rsi, g.allocate_string('$e.val', 2)) // for rsi its 2
 | 
				
			||||||
 | 
												g.mov_reg_to_var(pos, .rsi)
 | 
				
			||||||
 | 
												pos += 8
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
											else {
 | 
				
			||||||
 | 
												dump(e)
 | 
				
			||||||
 | 
												verror('unhandled array init type')
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								ast.IndexExpr {
 | 
				
			||||||
 | 
									// a := arr[0]
 | 
				
			||||||
 | 
									offset := g.allocate_var(name, 4, 0)
 | 
				
			||||||
 | 
									if g.pref.is_verbose {
 | 
				
			||||||
 | 
										println('infix assignment $name offset=$offset.hex2()')
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									ie := node.right[i] as ast.IndexExpr
 | 
				
			||||||
 | 
									var_name := ie.left.str()
 | 
				
			||||||
 | 
									mut dest := g.get_var_offset(var_name)
 | 
				
			||||||
 | 
									index := ie.index as ast.IntegerLiteral
 | 
				
			||||||
 | 
									dest += index.val.int() * 8
 | 
				
			||||||
 | 
									// TODO check if out of bounds access
 | 
				
			||||||
 | 
									g.mov_var_to_reg(.rax, dest)
 | 
				
			||||||
 | 
									g.mov_reg_to_var(offset, .eax)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								ast.StringLiteral {
 | 
				
			||||||
 | 
									dest := g.allocate_var(name, 4, 0)
 | 
				
			||||||
 | 
									ie := node.right[i] as ast.StringLiteral
 | 
				
			||||||
 | 
									g.mov64(.rsi, g.allocate_string(ie.str(), 2)) // for rsi its 2
 | 
				
			||||||
 | 
									g.mov_reg_to_var(dest, .rsi)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								ast.CallExpr {
 | 
				
			||||||
 | 
									dest := g.allocate_var(name, 4, 0)
 | 
				
			||||||
 | 
									g.call_fn(right)
 | 
				
			||||||
 | 
									g.mov_reg_to_var(dest, .rax)
 | 
				
			||||||
 | 
									g.mov_var_to_reg(.rsi, dest)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			else {
 | 
								else {
 | 
				
			||||||
 | 
									// dump(node)
 | 
				
			||||||
				g.error_with_pos('native assign_stmt unhandled expr: ' + right.type_name(),
 | 
									g.error_with_pos('native assign_stmt unhandled expr: ' + right.type_name(),
 | 
				
			||||||
					right.position())
 | 
										right.position())
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					@ -559,12 +950,17 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn (mut g Gen) infix_expr(node ast.InfixExpr) {
 | 
					fn (mut g Gen) infix_expr(node ast.InfixExpr) {
 | 
				
			||||||
	println('infix expr op=$node.op')
 | 
						if g.pref.is_verbose {
 | 
				
			||||||
 | 
							println('infix expr op=$node.op')
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// TODO
 | 
				
			||||||
	if node.left is ast.InfixExpr {
 | 
						if node.left is ast.InfixExpr {
 | 
				
			||||||
		verror('only simple expressions are supported right now (not more than 2 operands)')
 | 
							verror('only simple expressions are supported right now (not more than 2 operands)')
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	match mut node.left {
 | 
						match mut node.left {
 | 
				
			||||||
		ast.Ident { g.mov_var_to_reg(.eax, g.get_var_offset(node.left.name)) }
 | 
							ast.Ident {
 | 
				
			||||||
 | 
								g.mov_var_to_reg(.eax, g.get_var_offset(node.left.name))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		else {}
 | 
							else {}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if mut node.right is ast.Ident {
 | 
						if mut node.right is ast.Ident {
 | 
				
			||||||
| 
						 | 
					@ -572,6 +968,7 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
 | 
				
			||||||
		match node.op {
 | 
							match node.op {
 | 
				
			||||||
			.plus { g.add8_var(.eax, var_offset) }
 | 
								.plus { g.add8_var(.eax, var_offset) }
 | 
				
			||||||
			.mul { g.mul8_var(.eax, var_offset) }
 | 
								.mul { g.mul8_var(.eax, var_offset) }
 | 
				
			||||||
 | 
								.div { g.div8_var(.eax, var_offset) }
 | 
				
			||||||
			.minus { g.sub8_var(.eax, var_offset) }
 | 
								.minus { g.sub8_var(.eax, var_offset) }
 | 
				
			||||||
			else {}
 | 
								else {}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -621,13 +1018,20 @@ fn (mut g Gen) for_stmt(node ast.ForStmt) {
 | 
				
			||||||
	g.jmp(int(0xffffffff - (g.pos() + 5 - start) + 1))
 | 
						g.jmp(int(0xffffffff - (g.pos() + 5 - start) + 1))
 | 
				
			||||||
	// Update the jump addr to current pos
 | 
						// Update the jump addr to current pos
 | 
				
			||||||
	g.write32_at(jump_addr, int(g.pos() - jump_addr - 4)) // 4 is for "00 00 00 00"
 | 
						g.write32_at(jump_addr, int(g.pos() - jump_addr - 4)) // 4 is for "00 00 00 00"
 | 
				
			||||||
	g.println('jpm after for')
 | 
						g.println('jmp after for')
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn (mut g Gen) fn_decl(node ast.FnDecl) {
 | 
					fn (mut g Gen) fn_decl(node ast.FnDecl) {
 | 
				
			||||||
	if g.pref.is_verbose {
 | 
						if g.pref.is_verbose {
 | 
				
			||||||
		println(term.green('\n$node.name:'))
 | 
							println(term.green('\n$node.name:'))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						// if g.is_method
 | 
				
			||||||
 | 
						if node.is_deprecated {
 | 
				
			||||||
 | 
							eprintln('fn_decl: $node.name is deprecated')
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if node.is_builtin {
 | 
				
			||||||
 | 
							eprintln('fn_decl: $node.name is builtin')
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	g.stack_var_pos = 0
 | 
						g.stack_var_pos = 0
 | 
				
			||||||
	is_main := node.name == 'main.main'
 | 
						is_main := node.name == 'main.main'
 | 
				
			||||||
	// println('saving addr $node.name $g.buf.len.hex2()')
 | 
						// println('saving addr $node.name $g.buf.len.hex2()')
 | 
				
			||||||
| 
						 | 
					@ -640,11 +1044,13 @@ fn (mut g Gen) fn_decl(node ast.FnDecl) {
 | 
				
			||||||
		g.fn_decl_arm64(node)
 | 
							g.fn_decl_arm64(node)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	g.push(.rbp)
 | 
						g.push(.rbp)
 | 
				
			||||||
	g.mov_rbp_rsp()
 | 
						g.mov_rbp_rsp()
 | 
				
			||||||
	// if !is_main {
 | 
						locals_count := node.scope.objects.len + node.params.len
 | 
				
			||||||
	g.sub8(.rsp, 0x10)
 | 
						stackframe_size := (locals_count * 8) + 0x10
 | 
				
			||||||
	// }
 | 
						g.sub8(.rsp, stackframe_size)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if node.params.len > 0 {
 | 
						if node.params.len > 0 {
 | 
				
			||||||
		// g.mov(.r12, 0x77777777)
 | 
							// g.mov(.r12, 0x77777777)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -656,7 +1062,7 @@ fn (mut g Gen) fn_decl(node ast.FnDecl) {
 | 
				
			||||||
		g.allocate_var(name, 4, 0)
 | 
							g.allocate_var(name, 4, 0)
 | 
				
			||||||
		// `mov DWORD PTR [rbp-0x4],edi`
 | 
							// `mov DWORD PTR [rbp-0x4],edi`
 | 
				
			||||||
		offset += 4
 | 
							offset += 4
 | 
				
			||||||
		g.mov_reg_to_rbp(offset, native.fn_arg_registers[i])
 | 
							g.mov_reg_to_var(offset, native.fn_arg_registers[i])
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	//
 | 
						//
 | 
				
			||||||
	g.stmts(node.stmts)
 | 
						g.stmts(node.stmts)
 | 
				
			||||||
| 
						 | 
					@ -664,10 +1070,11 @@ fn (mut g Gen) fn_decl(node ast.FnDecl) {
 | 
				
			||||||
		// println('end of main: gen exit')
 | 
							// println('end of main: gen exit')
 | 
				
			||||||
		zero := ast.IntegerLiteral{}
 | 
							zero := ast.IntegerLiteral{}
 | 
				
			||||||
		g.gen_exit(zero)
 | 
							g.gen_exit(zero)
 | 
				
			||||||
 | 
							g.ret()
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// g.leave()
 | 
						// g.leave()
 | 
				
			||||||
	g.add8(.rsp, 0x10)
 | 
						g.add8(.rsp, stackframe_size)
 | 
				
			||||||
	g.pop(.rbp)
 | 
						g.pop(.rbp)
 | 
				
			||||||
	g.ret()
 | 
						g.ret()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -676,7 +1083,13 @@ pub fn (mut x Amd64) allocate_var(name string, size int, initial_val int) {
 | 
				
			||||||
	// do nothing as interface call is crashing
 | 
						// do nothing as interface call is crashing
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn (mut g Gen) allocate_var(name string, size int, initial_val int) {
 | 
					pub fn (mut g Gen) allocate_array(name string, size int, items int) int {
 | 
				
			||||||
 | 
						pos := g.allocate_var(name, size, items)
 | 
				
			||||||
 | 
						g.stack_var_pos += (size * items)
 | 
				
			||||||
 | 
						return pos
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn (mut g Gen) allocate_var(name string, size int, initial_val int) int {
 | 
				
			||||||
	// `a := 3`  =>
 | 
						// `a := 3`  =>
 | 
				
			||||||
	// `move DWORD [rbp-0x4],0x3`
 | 
						// `move DWORD [rbp-0x4],0x3`
 | 
				
			||||||
	match size {
 | 
						match size {
 | 
				
			||||||
| 
						 | 
					@ -709,4 +1122,5 @@ pub fn (mut g Gen) allocate_var(name string, size int, initial_val int) {
 | 
				
			||||||
	g.write32(initial_val)
 | 
						g.write32(initial_val)
 | 
				
			||||||
	// println('allocate_var(size=$size, initial_val=$initial_val)')
 | 
						// println('allocate_var(size=$size, initial_val=$initial_val)')
 | 
				
			||||||
	g.println('mov DWORD [rbp-$n.hex2()],$initial_val (Allocate var `$name`)')
 | 
						g.println('mov DWORD [rbp-$n.hex2()],$initial_val (Allocate var `$name`)')
 | 
				
			||||||
 | 
						return g.stack_var_pos
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -221,7 +221,7 @@ fn (mut g Gen) write_string_with_padding(s string, max int) {
 | 
				
			||||||
fn (mut g Gen) get_var_offset(var_name string) int {
 | 
					fn (mut g Gen) get_var_offset(var_name string) int {
 | 
				
			||||||
	offset := g.var_offset[var_name]
 | 
						offset := g.var_offset[var_name]
 | 
				
			||||||
	if offset == 0 {
 | 
						if offset == 0 {
 | 
				
			||||||
		panic('0 offset for var `$var_name`')
 | 
							verror('unknown variable `$var_name`')
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return offset
 | 
						return offset
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -235,13 +235,24 @@ pub fn (mut g Gen) gen_print_from_expr(expr ast.Expr, newline bool) {
 | 
				
			||||||
				g.gen_print(expr.val)
 | 
									g.gen_print(expr.val)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		else {}
 | 
							ast.CallExpr {
 | 
				
			||||||
 | 
								g.call_fn(expr)
 | 
				
			||||||
 | 
								g.gen_print_reg(.rax, 3)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							ast.Ident {
 | 
				
			||||||
 | 
								g.expr(expr)
 | 
				
			||||||
 | 
								g.gen_print_reg(.rax, 3)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else {
 | 
				
			||||||
 | 
								dump(expr)
 | 
				
			||||||
 | 
								verror('expected string as argument for print')
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn (mut g Gen) register_function_address(name string) {
 | 
					pub fn (mut g Gen) register_function_address(name string) {
 | 
				
			||||||
	addr := g.pos()
 | 
						addr := g.pos()
 | 
				
			||||||
	// println('reg fn addr $name $addr')
 | 
						// eprintln('register function $name = $addr')
 | 
				
			||||||
	g.fn_addr[name] = addr
 | 
						g.fn_addr[name] = addr
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -325,10 +336,36 @@ fn (mut g Gen) stmt(node ast.Stmt) {
 | 
				
			||||||
				g.write8(b)
 | 
									g.write8(b)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ast.Module {}
 | 
							ast.Module {
 | 
				
			||||||
 | 
								eprintln('module')
 | 
				
			||||||
 | 
								dump(node)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		ast.Return {
 | 
							ast.Return {
 | 
				
			||||||
			zero := ast.IntegerLiteral{}
 | 
								// dump(node.exprs[0])
 | 
				
			||||||
			g.gen_exit(zero)
 | 
								// if in main
 | 
				
			||||||
 | 
								// zero := ast.IntegerLiteral{}
 | 
				
			||||||
 | 
								// g.gen_exit(zero)
 | 
				
			||||||
 | 
								dump(node)
 | 
				
			||||||
 | 
								dump(node.types)
 | 
				
			||||||
 | 
								mut s := '?' //${node.exprs[0].val.str()}'
 | 
				
			||||||
 | 
								e0 := node.exprs[0]
 | 
				
			||||||
 | 
								match e0 {
 | 
				
			||||||
 | 
									ast.IntegerLiteral {
 | 
				
			||||||
 | 
										// TODO
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									ast.StringLiteral {
 | 
				
			||||||
 | 
										s = e0.val.str()
 | 
				
			||||||
 | 
										eprintln('jlalala $s')
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									else {
 | 
				
			||||||
 | 
										verror('unknown return type')
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								g.expr(node.exprs[0])
 | 
				
			||||||
 | 
								g.mov64(.rax, g.allocate_string(s, 2))
 | 
				
			||||||
 | 
								// intel specific
 | 
				
			||||||
 | 
								g.add8(.rsp, 0x20) // XXX depends on scope frame size
 | 
				
			||||||
 | 
								g.pop(.rbp)
 | 
				
			||||||
			g.ret()
 | 
								g.ret()
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ast.StructDecl {}
 | 
							ast.StructDecl {}
 | 
				
			||||||
| 
						 | 
					@ -342,7 +379,9 @@ fn C.strtol(str &char, endptr &&char, base int) int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn (mut g Gen) expr(node ast.Expr) {
 | 
					fn (mut g Gen) expr(node ast.Expr) {
 | 
				
			||||||
	match node {
 | 
						match node {
 | 
				
			||||||
		ast.ArrayInit {}
 | 
							ast.ArrayInit {
 | 
				
			||||||
 | 
								verror('array init expr not supported yet')
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		ast.BoolLiteral {}
 | 
							ast.BoolLiteral {}
 | 
				
			||||||
		ast.CallExpr {
 | 
							ast.CallExpr {
 | 
				
			||||||
			if node.name == 'exit' {
 | 
								if node.name == 'exit' {
 | 
				
			||||||
| 
						 | 
					@ -391,6 +430,8 @@ fn (mut g Gen) postfix_expr(node ast.PostfixExpr) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// not yet supported
 | 
				
			||||||
 | 
					[noreturn]
 | 
				
			||||||
fn verror(s string) {
 | 
					fn verror(s string) {
 | 
				
			||||||
	util.verror('native gen error', s)
 | 
						util.verror('native gen error', s)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -44,7 +44,7 @@ fn test_add() {
 | 
				
			||||||
	y := 3
 | 
						y := 3
 | 
				
			||||||
	sum := x + y
 | 
						sum := x + y
 | 
				
			||||||
	product := x * y
 | 
						product := x * y
 | 
				
			||||||
	diff := y - x
 | 
						// diff := y - x
 | 
				
			||||||
	print_number(x)
 | 
						print_number(x)
 | 
				
			||||||
	print_number(y)
 | 
						print_number(y)
 | 
				
			||||||
	print_number(sum)
 | 
						print_number(sum)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue