diff --git a/0.2_roadmap.txt b/0.2_roadmap.txt index 63fb5201c3..20afb921f5 100644 --- a/0.2_roadmap.txt +++ b/0.2_roadmap.txt @@ -38,11 +38,10 @@ - declarative ui with hot reload (similar to swiftui) - "building a simple blog with vweb" tutorial + youtube video + fix interfaces -- merge v.c and v_win.c + fast.vlang.io + bare metal support + inline assembly + x64 machine code generation (ELF) -- require explicit C.fn definitions, add all missing definitions ++ require explicit C.fn definitions, add all missing definitions diff --git a/examples/x64/hello_world.v b/examples/x64/hello_world.v index bd47cd8611..6bda7a20f3 100644 --- a/examples/x64/hello_world.v +++ b/examples/x64/hello_world.v @@ -1,11 +1,14 @@ +fn test_fn() { + println('test fn') +} + fn main() { println('x64 test') for _ in 0..5 { println('Hello world from V x64 machine code generator!') } println('Hello again!') + test_fn() + println('dne') } -fn test_fn() { - println('test fn') -} diff --git a/vlib/builtin/string_test.v b/vlib/builtin/string_test.v index 6cc6ff6f16..7e69a44967 100644 --- a/vlib/builtin/string_test.v +++ b/vlib/builtin/string_test.v @@ -93,7 +93,7 @@ fn test_split() { assert vals.len == 2 assert vals[0] == 'volt/twitch.v' assert vals[1] == '34' - // ///////// + // ///////// s = '2018-01-01z13:01:02' vals = s.split('z') assert vals.len == 2 @@ -491,13 +491,13 @@ fn test_raw() { lines := raw.split('\n') assert lines.len == 1 println('raw string: "$raw"') -} +} fn test_escape() { // TODO //a := 10 //println("\"$a") -} +} fn test_atoi() { assert '234232'.int() == 234232 @@ -506,8 +506,8 @@ fn test_atoi() { for n in -10000 .. 100000 { s := n.str() assert s.int() == n - } -} + } +} fn test_raw_inter() { world := 'world' @@ -523,6 +523,6 @@ fn test_c_r() { println('$c') r := 50 println('$r') - -} + +} diff --git a/vlib/compiler/cc.v b/vlib/compiler/cc.v index 8aceec585c..779b2a8bba 100644 --- a/vlib/compiler/cc.v +++ b/vlib/compiler/cc.v @@ -11,8 +11,8 @@ import ( ) fn todo() { - -} + +} fn no_mingw_installed() bool { $if !windows { @@ -48,16 +48,16 @@ fn (v mut V) cc() { } else { println('Failed.') exit(1) - } - } + } + } ret := os.system('$vjs_path -o $v.out_name $v.dir') if ret == 0 { println('Done. Run it with `node $v.out_name`') println('JS backend is at a very early stage.') - } + } } } - + // v.out_name_c may be on a different partition than v.out_name os.mv_by_cp(v.out_name_c, v.out_name) or { panic(err) } exit(0) @@ -116,7 +116,7 @@ fn (v mut V) cc() { } } $else { verror('-fast is only supported on Linux right now') - } + } } //linux_host := os.user_os() == 'linux' v.log('cc() isprod=$v.pref.is_prod outname=$v.out_name') @@ -127,11 +127,11 @@ fn (v mut V) cc() { } if v.pref.is_bare { a << '-static -ffreestanding -nostdlib $vdir/vlib/os/bare/bare.S' - } + } if v.pref.build_mode == .build_module { // Create the modules & out directory if it's not there. mut out_dir := if v.dir.starts_with('vlib') { - '$v_modules_path${os.path_separator}cache${os.path_separator}$v.dir' + '$v_modules_path${os.path_separator}cache${os.path_separator}$v.dir' } else { '$v_modules_path${os.path_separator}$v.dir' } @@ -158,14 +158,14 @@ fn (v mut V) cc() { } optimization_options = '-O3 -fno-strict-aliasing -flto' } - + if debug_mode { a << debug_options } if v.pref.is_prod { a << optimization_options } - + if debug_mode && os.user_os() != 'windows'{ a << ' -rdynamic ' // needed for nicer symbolic backtraces } @@ -194,7 +194,7 @@ fn (v mut V) cc() { for imp in v.table.imports { if imp.contains('vweb') { continue } // not working if imp == 'webview' { continue } - + imp_path := imp.replace('.', os.path_separator) path := '$v_modules_path${os.path_separator}cache${os.path_separator}vlib${os.path_separator}${imp_path}.o' //println('adding ${imp_path}.o') @@ -207,11 +207,11 @@ fn (v mut V) cc() { os.cp('$vdir/thirdparty/ui/ui.o', path) or { panic('error copying ui files') } os.cp('$vdir/thirdparty/ui/ui.vh', v_modules_path + '/vlib/ui.vh') or { panic('error copying ui files') } - + } else { os.system('$vexe build module vlib${os.path_separator}$imp_path') } - } + } if path.ends_with('vlib/ui.o') { a << '-framework Cocoa -framework Carbon' } @@ -256,10 +256,10 @@ fn (v mut V) cc() { // add .o files a << cflags.c_options_only_object_files() - + // add all flags (-I -l -L etc) not .o files a << cflags.c_options_without_object_files() - + a << libs // Without these libs compilation will fail on Linux // || os.user_os() == 'linux' @@ -275,7 +275,7 @@ fn (v mut V) cc() { if v.os == .js && os.user_os() == 'linux' { a << '-lm' } - + args := a.join(' ') start: todo() @@ -309,14 +309,16 @@ start: if v.pref.ccompiler.contains('tcc') { v.pref.ccompiler = 'cc' goto start - } + } } + verror('C compiler error, while attempting to run: \n' + '-----------------------------------------------------------\n' + '$cmd\n' + '-----------------------------------------------------------\n' + 'Probably your C compiler is missing. \n' + - 'Please reinstall it, or make it available in your PATH.') + 'Please reinstall it, or make it available in your PATH.\n\n' + + missing_compiler_info()) } if v.pref.is_debug { @@ -368,7 +370,7 @@ start: $if windows { println('-compress does not work on Windows for now') return - } + } ret := os.system('strip $v.out_name') if ret != 0 { println('strip failed') @@ -379,16 +381,16 @@ start: println('upx failed') $if mac { println('install upx with `brew install upx`') - } + } $if linux { println('install upx\n' + 'for example, on Debian/Ubuntu run `sudo apt install upx`') - } + } $if windows { // :) - } + } } - } + } } @@ -430,7 +432,7 @@ fn (c mut V) cc_windows_cross() { println('Unzip it afterwards.\n') println('winroot.zip contains all library and header files needed '+ 'to cross-compile for Windows.') - exit(1) + exit(1) } mut obj_name := c.out_name obj_name = obj_name.replace('.exe', '') @@ -463,7 +465,7 @@ fn (c mut V) cc_windows_cross() { fn (c &V) build_thirdparty_obj_files() { for flag in c.get_os_cflags() { - if flag.value.ends_with('.o') { + if flag.value.ends_with('.o') { rest_of_module_flags := c.get_rest_of_module_cflags( flag ) if c.pref.ccompiler == 'msvc' { build_thirdparty_obj_file_with_msvc(flag.value, rest_of_module_flags) @@ -512,3 +514,16 @@ fn get_cmdline_cflags(args []string) string { } return cflags } + +fn missing_compiler_info() string { + $if windows { + return 'https://github.com/vlang/v/wiki/Installing-a-C-compiler-on-Windows' + } + $if linux { + return 'On Debian/Ubuntu, run `sudo apt install build-essential`' + } + $if mac { + return 'Install command line XCode tools with `xcode-select --install`' + } + return '' +} diff --git a/vlib/compiler/fn.v b/vlib/compiler/fn.v index bf89ac1ad5..3617dad5b1 100644 --- a/vlib/compiler/fn.v +++ b/vlib/compiler/fn.v @@ -512,6 +512,9 @@ fn (p mut Parser) fn_decl() { f.defer_text[f.scope_level] = ' ${cgen_name}_time += time__ticks() - _PROF_START;' } } + if p.pref.x64 { + p.x64.register_function_address(f.name) + } p.statements_no_rcbr() //p.cgen.nogen = false // Print counting result after all statements in main @@ -712,6 +715,9 @@ fn (p mut Parser) fn_call(f mut Fn, method_ph int, receiver_var, receiver_type s if is_comptime_define { p.cgen.nogen = true } + if p.pref.x64 && !p.first_pass() { + p.x64.call_fn(f.name) + } p.calling_c = f.is_c if f.is_c && !p.builtin_mod { if f.name == 'free' { diff --git a/vlib/compiler/x64/gen.v b/vlib/compiler/x64/gen.v index 6c49f64b17..35016c07c0 100644 --- a/vlib/compiler/x64/gen.v +++ b/vlib/compiler/x64/gen.v @@ -15,6 +15,7 @@ mut: file_size_pos i64 main_fn_addr i64 code_start_pos i64 // location of the start of the assembly instructions + fn_addr map[string]i64 //string_addr map[string]i64 } @@ -44,6 +45,10 @@ pub fn new_gen(out_name string) &Gen { } } +pub fn (g &Gen) pos() i64 { + return g.buf.len +} + fn (g mut Gen) write8(n int) { // write 1 byte @@ -155,10 +160,13 @@ fn (g mut Gen) mov64(reg Register, val i64) { g.write64(val) } -fn (g mut Gen) call(val int) { - //println('call val=$val') +fn (g mut Gen) call(addr int) { + //rel := g.abs_to_rel_addr(addr) + rel := 0xffffffff - int(abs(addr - g.buf.len))-1 + + println('call addr=$addr rel_addr=$addr pos=$g.buf.len') g.write8(0xe8) - g.write32(val) + g.write32(addr) } fn (g mut Gen) syscall() { @@ -228,4 +236,19 @@ fn (g mut Gen) mov(reg Register, val int) { g.write32(val) } +pub fn (g mut Gen) register_function_address(name string) { + addr := g.pos() + println('reg fn addr $name $addr') + g.fn_addr[name] = addr +} + +pub fn (g mut Gen) call_fn(name string) { + if !name.contains('__') { + return + } + addr := g.fn_addr[name] + g.call(int(addr)) + println('call $name $addr') +} +