mirror of
				https://github.com/janet-lang/janet
				synced 2025-10-30 23:23:07 +00:00 
			
		
		
		
	More work on x86 backend.
This commit is contained in:
		| @@ -7,13 +7,17 @@ | |||||||
|  |  | ||||||
| (use ./frontend) | (use ./frontend) | ||||||
|  |  | ||||||
|  | (setdyn :verbose true) | ||||||
|  |  | ||||||
|  | # Pointer types | ||||||
| (defpointer p32 uint) | (defpointer p32 uint) | ||||||
| (defpointer p16 u16) | (defpointer p16 u16) | ||||||
| (defpointer cursor p32) | (defpointer cursor p32) | ||||||
| (defn-external write:void [fd:int mem:pointer size:uint]) |  | ||||||
| (defn-external exit:void [x:int]) | # Linux syscalls | ||||||
| (defn-external malloc:p32 [x:uint]) | (defn-syscall brk:p32 12 [amount:uint]) | ||||||
| (defn-external free:void [m:p32]) | (defn-syscall exit:void 60 [code:int]) | ||||||
|  | (defn-syscall write:void 1 [fd:int data:p32 size:uint]) | ||||||
|  |  | ||||||
| (defsys w32:void [c:cursor x:uint] | (defsys w32:void [c:cursor x:uint] | ||||||
|   (def p:p32 (load c)) |   (def p:p32 (load c)) | ||||||
| @@ -30,9 +34,11 @@ | |||||||
|  |  | ||||||
| (defsys makebmp:p32 [w:uint h:uint] | (defsys makebmp:p32 [w:uint h:uint] | ||||||
|   (def size:uint (+ 56 (* w h 4))) |   (def size:uint (+ 56 (* w h 4))) | ||||||
|   (def mem:p32 (malloc size)) |   (def mem:p32 (brk size)) | ||||||
|   (def cursor_data:p32 mem) |   #(def cursor_data:p32 mem) | ||||||
|   (def c:cursor (address cursor_data)) |   #(def c:cursor (address cursor_data)) | ||||||
|  |   (def c:cursor (cast (brk 4))) | ||||||
|  |   (store c mem) | ||||||
|   (w16 c 0x4D42) # ascii "BM" |   (w16 c 0x4D42) # ascii "BM" | ||||||
|   (w32 c size) |   (w32 c size) | ||||||
|   (w32 c 0) |   (w32 c 0) | ||||||
| @@ -52,27 +58,32 @@ | |||||||
|   # Draw |   # Draw | ||||||
|   (def red:uint 0xFFFF0000) |   (def red:uint 0xFFFF0000) | ||||||
|   (def blue:uint 0xFF0000FF) |   (def blue:uint 0xFF0000FF) | ||||||
|  |   (def green:uint 0xFF00FF00) | ||||||
|   (var y:uint 0) |   (var y:uint 0) | ||||||
|   (while (< y h) |   (while (< y h) | ||||||
|     (var x:uint 0) |     (var x:uint 0) | ||||||
|     (while (< x w) |     (while (< x w) | ||||||
|       (if (> y 64) |       (def d2:uint (+ (* x x) (* y y))) | ||||||
|         (w32 c blue) |       (if (> d2 100000) | ||||||
|  |         (if (> d2 200000) (w32 c green) (w32 c blue)) | ||||||
|         (w32 c red)) |         (w32 c red)) | ||||||
|       (set x (+ 1 x))) |       (set x (+ 1 x))) | ||||||
|     (set y (+ y 1))) |     (set y (+ y 1))) | ||||||
|   (write 1 mem size) |   (write 1 mem size) | ||||||
|   (return mem)) |   (return mem)) | ||||||
|  |  | ||||||
| (defsys main:int [] | (defsys _start:void [] | ||||||
|   (def w:uint 128) |   (def w:uint 512) | ||||||
|   (def h:uint 512) |   (def h:uint 512) | ||||||
|   (makebmp w h) |   # (makebmp w h) | ||||||
|   (return 0)) |   (def size:uint (+ 56 (* w h 4))) | ||||||
|  |   (def mem:p32 (brk size)) | ||||||
|  |   (store mem (the uint 0x4d424d42)) | ||||||
|  |   (write 1 mem 4) | ||||||
|  |   #(write 1 (cast "hello, world!\n") 14) | ||||||
|  |   (exit 0) | ||||||
|  |   (return)) | ||||||
|  |  | ||||||
| #### | #### | ||||||
|  |  | ||||||
| #(dump) | (dumpx64) | ||||||
| (print "#include <unistd.h>") |  | ||||||
| (dumpc) |  | ||||||
| #(dumpx64) |  | ||||||
|   | |||||||
| @@ -12,6 +12,7 @@ | |||||||
| (def slot-types @{}) | (def slot-types @{}) | ||||||
| (def functions @{}) | (def functions @{}) | ||||||
| (def type-fields @{}) | (def type-fields @{}) | ||||||
|  | (def syscalls @{}) | ||||||
|  |  | ||||||
| (defn get-slot | (defn get-slot | ||||||
|   [&opt new-name] |   [&opt new-name] | ||||||
| @@ -317,20 +318,11 @@ | |||||||
|             (array/push into ;args) |             (array/push into ;args) | ||||||
|             nil) |             nil) | ||||||
|  |  | ||||||
|           # Syscall |           # Assume function call or syscall | ||||||
|           'syscall |  | ||||||
|           (do |  | ||||||
|             (def slots @[]) |  | ||||||
|             (def ret (if no-return nil (get-slot))) |  | ||||||
|             (each arg args |  | ||||||
|               (array/push slots (visit1 arg into))) |  | ||||||
|             (array/push into ~(syscall :default ,ret ,;slots)) |  | ||||||
|             ret) |  | ||||||
|  |  | ||||||
|           # Assume function call |  | ||||||
|           (do |           (do | ||||||
|             (def slots @[]) |             (def slots @[]) | ||||||
|             (def signature (get functions op)) |             (def signature (get functions op)) | ||||||
|  |             (def is-syscall (get syscalls op)) | ||||||
|             (assert signature (string "unknown function " op)) |             (assert signature (string "unknown function " op)) | ||||||
|             (def ret (if no-return nil (get-slot))) |             (def ret (if no-return nil (get-slot))) | ||||||
|             (when ret |             (when ret | ||||||
| @@ -338,7 +330,9 @@ | |||||||
|               (assign-type ret (first signature))) |               (assign-type ret (first signature))) | ||||||
|             (each [arg-type arg] (map tuple (drop 1 signature) args) |             (each [arg-type arg] (map tuple (drop 1 signature) args) | ||||||
|               (array/push slots (visit1 arg into false arg-type))) |               (array/push slots (visit1 arg into false arg-type))) | ||||||
|             (array/push into ~(call :default ,ret [pointer ,op] ,;slots)) |             (if is-syscall | ||||||
|  |               (array/push into ~(syscall :default ,ret (int ,is-syscall) ,;slots)) | ||||||
|  |               (array/push into ~(call :default ,ret [pointer ,op] ,;slots))) | ||||||
|             ret))) |             ret))) | ||||||
|  |  | ||||||
|       (errorf "cannot compile %q" code))) |       (errorf "cannot compile %q" code))) | ||||||
| @@ -478,6 +472,20 @@ | |||||||
|         (array/push signature tp)) |         (array/push signature tp)) | ||||||
|       (put functions fn-name (freeze signature))) |       (put functions fn-name (freeze signature))) | ||||||
|  |  | ||||||
|  |     # External syscall | ||||||
|  |     'defn-syscall | ||||||
|  |     (do | ||||||
|  |       (def [name sysnum args] rest) | ||||||
|  |       (assert (tuple? args)) | ||||||
|  |       (def [fn-name fn-tp] (type-extract name 'void)) | ||||||
|  |       (def pcount (length args)) #TODO - more complicated signatures | ||||||
|  |       (def signature @[fn-tp]) | ||||||
|  |       (each arg args | ||||||
|  |         (def [name tp] (type-extract arg 'int)) | ||||||
|  |         (array/push signature tp)) | ||||||
|  |       (put syscalls fn-name sysnum) | ||||||
|  |       (put functions fn-name (freeze signature))) | ||||||
|  |  | ||||||
|     # Top level function definition |     # Top level function definition | ||||||
|     'defn |     'defn | ||||||
|     (do |     (do | ||||||
| @@ -544,4 +552,5 @@ | |||||||
| (defmacro defarray [& args] [compile1 ~',(keep-syntax! (dyn *macro-form*) ~(defarray ,;args))]) | (defmacro defarray [& args] [compile1 ~',(keep-syntax! (dyn *macro-form*) ~(defarray ,;args))]) | ||||||
| (defmacro defpointer [& args] [compile1 ~',(keep-syntax! (dyn *macro-form*) ~(defpointer ,;args))]) | (defmacro defpointer [& args] [compile1 ~',(keep-syntax! (dyn *macro-form*) ~(defpointer ,;args))]) | ||||||
| (defmacro defn-external [& args] [compile1 ~',(keep-syntax! (dyn *macro-form*) ~(defn-external ,;args))]) | (defmacro defn-external [& args] [compile1 ~',(keep-syntax! (dyn *macro-form*) ~(defn-external ,;args))]) | ||||||
|  | (defmacro defn-syscall [& args] [compile1 ~',(keep-syntax! (dyn *macro-form*) ~(defn-syscall ,;args))]) | ||||||
| (defmacro defsys [& args] [compile1 ~',(keep-syntax! (dyn *macro-form*) ~(defn ,;args))]) | (defmacro defsys [& args] [compile1 ~',(keep-syntax! (dyn *macro-form*) ~(defn ,;args))]) | ||||||
|   | |||||||
							
								
								
									
										5
									
								
								examples/sysir/run_drawing2.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										5
									
								
								examples/sysir/run_drawing2.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | #!/usr/bin/env bash | ||||||
|  | valgrind build/janet examples/sysir/drawing2.janet > temp.nasm | ||||||
|  | nasm -felf64 temp.nasm -l temp.lst -o temp.o | ||||||
|  | ld -o temp.bin -dynamic-linker /lib64/ld-linux-x86-64.so.2 -lc temp.o | ||||||
|  | valgrind ./temp.bin | ||||||
| @@ -158,10 +158,12 @@ static x64RegKind get_slot_regkind(JanetSysx64Context *ctx, uint32_t o) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void assign_registers(JanetSysx64Context *ctx) { | void assign_registers(JanetSysx64Context *ctx) { | ||||||
|  |  | ||||||
|     /* simplest register assignment algorithm - first n variables |     /* simplest register assignment algorithm - first n variables | ||||||
|      * get registers, rest get assigned temporary registers and spill on every use. */ |      * get registers, rest get assigned temporary registers and spill on every use. */ | ||||||
|  |     /* TODO - add option to allocate ALL variables on stack. Makes debugging easier. */ | ||||||
|     /* TODO - linear scan or graph coloring. Require calculating live ranges */ |     /* TODO - linear scan or graph coloring. Require calculating live ranges */ | ||||||
|     /* TODO - avoid spills inside loops if possible i.e. not all spills are equal */ |     /* TODO - avoid spills inside loops if possible i.e. not all spills are equal */ | ||||||
|     /* TODO - move into sysir.c and allow reuse for multiple targets */ |     /* TODO - move into sysir.c and allow reuse for multiple targets */ | ||||||
| @@ -175,7 +177,8 @@ void assign_registers(JanetSysx64Context *ctx) { | |||||||
|     uint32_t occupied = 0; |     uint32_t occupied = 0; | ||||||
|     assigned |= 1 << RSP; |     assigned |= 1 << RSP; | ||||||
|     assigned |= 1 << RBP; |     assigned |= 1 << RBP; | ||||||
|     assigned |= 1 << RAX; // return reg, div, etc. |     assigned |= 1 << RAX; // return reg, div, temporary, etc. | ||||||
|  |     assigned |= 1 << RBX; // another temp reg. | ||||||
|     for (uint32_t i = 0; i < ctx->ir->register_count; i++) { |     for (uint32_t i = 0; i < ctx->ir->register_count; i++) { | ||||||
|         ctx->regs[i].kind = get_slot_regkind(ctx, i); |         ctx->regs[i].kind = get_slot_regkind(ctx, i); | ||||||
|         if (i < ctx->ir->parameter_count) { |         if (i < ctx->ir->parameter_count) { | ||||||
| @@ -263,13 +266,37 @@ static int operand_isreg(JanetSysx64Context *ctx, uint32_t o, uint32_t regindex) | |||||||
|     return reg.index == regindex; |     return reg.index == regindex; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static const char *sysemit_sizestr(x64RegKind kind) { | ||||||
|  |     switch (kind) { | ||||||
|  |         case JANET_SYSREG_8: | ||||||
|  |             return "byte"; | ||||||
|  |         case JANET_SYSREG_16: | ||||||
|  |             return "word"; | ||||||
|  |         case JANET_SYSREG_32: | ||||||
|  |             return "dword"; | ||||||
|  |         case JANET_SYSREG_64: | ||||||
|  |             return "qword"; | ||||||
|  |         default: | ||||||
|  |             return "qword"; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static const char *sysemit_sizestr_reg(x64Reg reg) { | ||||||
|  |     return sysemit_sizestr(reg.kind); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static const char *sysemit_sizestr_slot(JanetSysx64Context *ctx, uint32_t slot) { | ||||||
|  |     return sysemit_sizestr(get_slot_regkind(ctx, slot)); | ||||||
|  | } | ||||||
|  |  | ||||||
| static void sysemit_reg(JanetSysx64Context *ctx, x64Reg reg, const char *after) { | static void sysemit_reg(JanetSysx64Context *ctx, x64Reg reg, const char *after) { | ||||||
|  |     const char *sizestr = sysemit_sizestr_reg(reg); | ||||||
|     if (reg.storage == JANET_SYSREG_STACK) { |     if (reg.storage == JANET_SYSREG_STACK) { | ||||||
|         // TODO - use LEA for parameters larger than a qword |         // TODO - use LEA for parameters larger than a qword | ||||||
|         janet_formatb(ctx->buffer, "[rbp-%u]", reg.index); |         janet_formatb(ctx->buffer, "%s [rbp-%u]", sizestr, reg.index); | ||||||
|     } else if (reg.storage == JANET_SYSREG_STACK_PARAMETER) { |     } else if (reg.storage == JANET_SYSREG_STACK_PARAMETER) { | ||||||
|         // TODO - use LEA for parameters larger than a qword |         // TODO - use LEA for parameters larger than a qword | ||||||
|         janet_formatb(ctx->buffer, "[rbp+%u]", reg.index); |         janet_formatb(ctx->buffer, "%s [rbp+%u]", sizestr, reg.index); | ||||||
|     } else if (reg.kind == JANET_SYSREG_64) { |     } else if (reg.kind == JANET_SYSREG_64) { | ||||||
|         janet_formatb(ctx->buffer, "%s", register_names[reg.index]); |         janet_formatb(ctx->buffer, "%s", register_names[reg.index]); | ||||||
|     } else if (reg.kind == JANET_SYSREG_32) { |     } else if (reg.kind == JANET_SYSREG_32) { | ||||||
| @@ -310,6 +337,7 @@ static void sysemit_binop(JanetSysx64Context *ctx, const char *op, uint32_t dest | |||||||
|     if (operand_isstack(ctx, dest) && operand_isstack(ctx, src)) { |     if (operand_isstack(ctx, dest) && operand_isstack(ctx, src)) { | ||||||
|         /* Use a temporary register for src */ |         /* Use a temporary register for src */ | ||||||
|         x64Reg tempreg; |         x64Reg tempreg; | ||||||
|  |         tempreg.storage = JANET_SYSREG_REGISTER; | ||||||
|         tempreg.kind = get_slot_regkind(ctx, dest); |         tempreg.kind = get_slot_regkind(ctx, dest); | ||||||
|         tempreg.index = RAX; |         tempreg.index = RAX; | ||||||
|         janet_formatb(ctx->buffer, "mov "); |         janet_formatb(ctx->buffer, "mov "); | ||||||
| @@ -325,6 +353,145 @@ static void sysemit_binop(JanetSysx64Context *ctx, const char *op, uint32_t dest | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* dest = src[0] */ | ||||||
|  | static void sysemit_load(JanetSysx64Context *ctx, uint32_t dest, uint32_t src) { | ||||||
|  |     /* This seems verbose... */ | ||||||
|  |     int src_is_stack = operand_isstack(ctx, src); | ||||||
|  |     int dest_is_stack = operand_isstack(ctx, dest); | ||||||
|  |     if (!src_is_stack && !dest_is_stack) { | ||||||
|  |         /* Simplest case */ | ||||||
|  |         janet_formatb(ctx->buffer, "mov "); | ||||||
|  |         sysemit_operand(ctx, dest, ", ["); | ||||||
|  |         sysemit_operand(ctx, src, "]\n"); | ||||||
|  |     } else if (src_is_stack && dest_is_stack) { | ||||||
|  |         /* Most complicated case. */ | ||||||
|  |         /* RAX = src */ | ||||||
|  |         /* RAX = RAX[0] */ | ||||||
|  |         /* dest = RAX */ | ||||||
|  |         /* Copy src to temp reg first */ | ||||||
|  |         x64Reg tempreg; | ||||||
|  |         tempreg.storage = JANET_SYSREG_REGISTER; | ||||||
|  |         tempreg.kind = get_slot_regkind(ctx, src); | ||||||
|  |         tempreg.index = RAX; | ||||||
|  |         janet_formatb(ctx->buffer, "mov "); | ||||||
|  |         sysemit_reg(ctx, tempreg, ", "); | ||||||
|  |         sysemit_operand(ctx, src, "\n"); | ||||||
|  |         /* Now to load to second tempreg */ | ||||||
|  |         x64Reg tempreg2; | ||||||
|  |         tempreg.storage = JANET_SYSREG_REGISTER; | ||||||
|  |         tempreg2.kind = get_slot_regkind(ctx, dest); | ||||||
|  |         tempreg2.index = RAX; /* We can reuse RAX */ | ||||||
|  |         janet_formatb(ctx->buffer, "mov "); | ||||||
|  |         sysemit_reg(ctx, tempreg2, ", ["); | ||||||
|  |         sysemit_reg(ctx, tempreg, "]\n"); | ||||||
|  |         /* Finally, move tempreg2 to dest */ | ||||||
|  |         /* Now move tempreg to dest */ | ||||||
|  |         janet_formatb(ctx->buffer, "mov "); | ||||||
|  |         sysemit_operand(ctx, dest, ", "); | ||||||
|  |         sysemit_reg(ctx, tempreg2, "\n"); | ||||||
|  |     } else if (src_is_stack) { | ||||||
|  |         /* RAX = src */ | ||||||
|  |         /* dest = RAX[0] */ | ||||||
|  |         /* Copy src to temp reg first */ | ||||||
|  |         x64Reg tempreg; | ||||||
|  |         tempreg.storage = JANET_SYSREG_REGISTER; | ||||||
|  |         tempreg.kind = get_slot_regkind(ctx, src); | ||||||
|  |         tempreg.index = RAX; | ||||||
|  |         janet_formatb(ctx->buffer, "mov "); | ||||||
|  |         sysemit_reg(ctx, tempreg, ", "); | ||||||
|  |         sysemit_operand(ctx, src, "\n"); | ||||||
|  |         /* Now do load to dest */ | ||||||
|  |         janet_formatb(ctx->buffer, "mov "); | ||||||
|  |         sysemit_operand(ctx, dest, ", ["); | ||||||
|  |         sysemit_reg(ctx, tempreg, "]\n"); | ||||||
|  |     } else { /* dest_is_stack */ | ||||||
|  |         /* RAX = src[0] */ | ||||||
|  |         /* dest = RAX */ | ||||||
|  |         /* Copy temp reg to dest after */ | ||||||
|  |         /* Load to tempreg first */ | ||||||
|  |         x64Reg tempreg; | ||||||
|  |         tempreg.storage = JANET_SYSREG_REGISTER; | ||||||
|  |         tempreg.kind = get_slot_regkind(ctx, src); | ||||||
|  |         tempreg.index = RAX; | ||||||
|  |         janet_formatb(ctx->buffer, "mov "); | ||||||
|  |         sysemit_reg(ctx, tempreg, ", ["); | ||||||
|  |         sysemit_operand(ctx, src, "]\n"); | ||||||
|  |         /* Now move tempreg to dest */ | ||||||
|  |         janet_formatb(ctx->buffer, "mov "); | ||||||
|  |         sysemit_operand(ctx, dest, ", "); | ||||||
|  |         sysemit_reg(ctx, tempreg, "\n"); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* dest[0] = src */ | ||||||
|  | static void sysemit_store(JanetSysx64Context *ctx, uint32_t dest, uint32_t src) { | ||||||
|  |     /* This seems verbose... */ | ||||||
|  |     int src_is_stack = operand_isstack(ctx, src); | ||||||
|  |     int dest_is_stack = operand_isstack(ctx, dest); | ||||||
|  |     const char *store_size = sysemit_sizestr_slot(ctx, src); | ||||||
|  |     if (!src_is_stack && !dest_is_stack) { | ||||||
|  |         /* Simplest case */ | ||||||
|  |         janet_formatb(ctx->buffer, "mov %s [", store_size); | ||||||
|  |         sysemit_operand(ctx, dest, "], "); | ||||||
|  |         sysemit_operand(ctx, src, "\n"); | ||||||
|  |     } else if (src_is_stack && dest_is_stack) { | ||||||
|  |         /* Most complicated case. */ | ||||||
|  |         /* dest = RAX */ | ||||||
|  |         /* src = RBX */ | ||||||
|  |         /* RAX = RBX[0] */ | ||||||
|  |         /* Copy dest to temp reg first */ | ||||||
|  |         x64Reg tempreg; | ||||||
|  |         tempreg.storage = JANET_SYSREG_REGISTER; | ||||||
|  |         tempreg.kind = get_slot_regkind(ctx, dest); | ||||||
|  |         tempreg.index = RAX; | ||||||
|  |         janet_formatb(ctx->buffer, "mov "); | ||||||
|  |         sysemit_reg(ctx, tempreg, ", "); | ||||||
|  |         sysemit_operand(ctx, dest, "\n"); | ||||||
|  |         /* Now to load to second tempreg */ | ||||||
|  |         x64Reg tempreg2; | ||||||
|  |         tempreg.storage = JANET_SYSREG_REGISTER; | ||||||
|  |         tempreg2.kind = get_slot_regkind(ctx, dest); | ||||||
|  |         tempreg2.index = RBX; | ||||||
|  |         janet_formatb(ctx->buffer, "mov "); | ||||||
|  |         sysemit_reg(ctx, tempreg2, ", "); | ||||||
|  |         sysemit_operand(ctx, src, "\n"); | ||||||
|  |         /* Finally, move tempreg2 to dest */ | ||||||
|  |         janet_formatb(ctx->buffer, "mov %s [", store_size); | ||||||
|  |         sysemit_reg(ctx, tempreg, "], "); | ||||||
|  |         sysemit_reg(ctx, tempreg2, "\n"); | ||||||
|  |     } else if (src_is_stack) { | ||||||
|  |         /* Copy src to temp reg first */ | ||||||
|  |         /* RAX = src */ | ||||||
|  |         /* dest[0] = RAX */ | ||||||
|  |         x64Reg tempreg; | ||||||
|  |         tempreg.storage = JANET_SYSREG_REGISTER; | ||||||
|  |         tempreg.kind = get_slot_regkind(ctx, src); | ||||||
|  |         tempreg.index = RAX; | ||||||
|  |         janet_formatb(ctx->buffer, "mov "); | ||||||
|  |         sysemit_reg(ctx, tempreg, ", "); | ||||||
|  |         sysemit_operand(ctx, src, "\n"); | ||||||
|  |         /* Now do load to dest */ | ||||||
|  |         janet_formatb(ctx->buffer, "mov %s [", store_size); | ||||||
|  |         sysemit_operand(ctx, dest, "], "); | ||||||
|  |         sysemit_reg(ctx, tempreg, "\n"); | ||||||
|  |     } else { /* dest_is_stack */ | ||||||
|  |         /* Copy temp reg to dest after */ | ||||||
|  |         /* RAX = dest */ | ||||||
|  |         /* RAX[0] = src */ | ||||||
|  |         /* Load to tempreg first */ | ||||||
|  |         x64Reg tempreg; | ||||||
|  |         tempreg.storage = JANET_SYSREG_REGISTER; | ||||||
|  |         tempreg.kind = get_slot_regkind(ctx, dest); | ||||||
|  |         tempreg.index = RAX; | ||||||
|  |         janet_formatb(ctx->buffer, "mov "); | ||||||
|  |         sysemit_reg(ctx, tempreg, ", "); | ||||||
|  |         sysemit_operand(ctx, dest, "\n"); | ||||||
|  |         janet_formatb(ctx->buffer, "mov %s [", store_size); | ||||||
|  |         sysemit_reg(ctx, tempreg, "], "); | ||||||
|  |         sysemit_operand(ctx, src, "\n"); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| static void sysemit_mov(JanetSysx64Context *ctx, uint32_t dest, uint32_t src) { | static void sysemit_mov(JanetSysx64Context *ctx, uint32_t dest, uint32_t src) { | ||||||
|     if (dest == src) return; |     if (dest == src) return; | ||||||
|     sysemit_binop(ctx, "mov", dest, src); |     sysemit_binop(ctx, "mov", dest, src); | ||||||
| @@ -458,7 +625,22 @@ static void sysemit_cast(JanetSysx64Context *ctx, JanetSysInstruction instructio | |||||||
|      */ |      */ | ||||||
|     (void) destinfo; |     (void) destinfo; | ||||||
|     (void) srcinfo; |     (void) srcinfo; | ||||||
|     janet_formatb(ctx->buffer, "; cast nyi\n"); |     x64RegKind srckind = get_slot_regkind(ctx, src); | ||||||
|  |     x64RegKind destkind = get_slot_regkind(ctx, dest); | ||||||
|  |     if (srckind == destkind) { | ||||||
|  |         sysemit_mov(ctx, dest, src); | ||||||
|  |     } else { | ||||||
|  |         uint32_t regindex = RAX; | ||||||
|  |         /* Check if we can optimize out temporary register */ | ||||||
|  |         if (src <= JANET_SYS_MAX_OPERAND) { | ||||||
|  |             x64Reg reg = ctx->regs[src]; | ||||||
|  |             if (reg.storage == JANET_SYSREG_REGISTER) { | ||||||
|  |                 regindex = reg.index; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         sysemit_movreg(ctx, regindex, src); | ||||||
|  |         sysemit_movfromreg(ctx, dest, regindex); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| static void sysemit_sysv_call(JanetSysx64Context *ctx, JanetSysInstruction instruction, uint32_t *args, uint32_t argcount) { | static void sysemit_sysv_call(JanetSysx64Context *ctx, JanetSysInstruction instruction, uint32_t *args, uint32_t argcount) { | ||||||
| @@ -638,6 +820,12 @@ void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetSysTarget target | |||||||
|                 default: |                 default: | ||||||
|                     janet_formatb(buffer, "; nyi: %s\n", janet_sysop_names[instruction.opcode]); |                     janet_formatb(buffer, "; nyi: %s\n", janet_sysop_names[instruction.opcode]); | ||||||
|                     break; |                     break; | ||||||
|  |                 case JANET_SYSOP_LOAD: | ||||||
|  |                     sysemit_load(&ctx, instruction.two.dest, instruction.two.src); | ||||||
|  |                     break; | ||||||
|  |                 case JANET_SYSOP_STORE: | ||||||
|  |                     sysemit_store(&ctx, instruction.two.dest, instruction.two.src); | ||||||
|  |                     break; | ||||||
|                 case JANET_SYSOP_TYPE_PRIMITIVE: |                 case JANET_SYSOP_TYPE_PRIMITIVE: | ||||||
|                 case JANET_SYSOP_TYPE_UNION: |                 case JANET_SYSOP_TYPE_UNION: | ||||||
|                 case JANET_SYSOP_TYPE_STRUCT: |                 case JANET_SYSOP_TYPE_STRUCT: | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Calvin Rose
					Calvin Rose