e576bb2002-10-11Martin Nilsson /* || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information.
b3575e2008-02-28Henrik Grubbström (Grubba) || $Id: sparc.c,v 1.50 2008/02/28 12:02:21 grubba Exp $
e576bb2002-10-11Martin Nilsson */
1b10db2002-10-08Martin Nilsson 
dd6bca2001-07-20Henrik Grubbström (Grubba) /* * Machine code generator for sparc. * * Henrik Grubbström 20010720 */
01de412002-11-08Henrik Grubbström (Grubba) #include "global.h" #include "svalue.h"
fc31002001-07-24Henrik Grubbström (Grubba) #include "operators.h"
01de412002-11-08Henrik Grubbström (Grubba) #include "object.h"
0dd1bc2003-04-18Martin Stjernholm #include "builtin_functions.h"
fc31002001-07-24Henrik Grubbström (Grubba) 
4f43322002-11-05Henrik Grubbström (Grubba) /* * Register definitions */ #define SPARC_REG_G0 0 #define SPARC_REG_G1 1 #define SPARC_REG_G2 2 #define SPARC_REG_G3 3 #define SPARC_REG_G4 4 #define SPARC_REG_G5 5 #define SPARC_REG_G6 6 #define SPARC_REG_G7 7 #define SPARC_REG_O0 8 #define SPARC_REG_O1 9 #define SPARC_REG_O2 10 #define SPARC_REG_O3 11 #define SPARC_REG_O4 12 #define SPARC_REG_O5 13 #define SPARC_REG_O6 14 /* SP */ #define SPARC_REG_O7 15 #define SPARC_REG_L0 16 #define SPARC_REG_L1 17 #define SPARC_REG_L2 18 #define SPARC_REG_L3 19 #define SPARC_REG_L4 20 #define SPARC_REG_L5 21 #define SPARC_REG_L6 22 #define SPARC_REG_L7 23 #define SPARC_REG_I0 24 #define SPARC_REG_I1 25 #define SPARC_REG_I2 26 #define SPARC_REG_I3 27 #define SPARC_REG_I4 28 #define SPARC_REG_I5 29 #define SPARC_REG_I6 30 /* FP */ #define SPARC_REG_I7 31 /* PC */ /*
0dc1b72002-11-06Henrik Grubbström (Grubba)  * ALU operations.
4f43322002-11-05Henrik Grubbström (Grubba)  */ #define SPARC_OP3_AND 0x01 #define SPARC_OP3_ANDcc 0x11 #define SPARC_OP3_ANDN 0x05 #define SPARC_OP3_ANDNcc 0x15 #define SPARC_OP3_OR 0x02 #define SPARC_OP3_ORcc 0x12 #define SPARC_OP3_ORN 0x06 #define SPARC_OP3_ORNcc 0x16 #define SPARC_OP3_XOR 0x03 #define SPARC_OP3_XORcc 0x13 #define SPARC_OP3_XNOR 0x07 #define SPARC_OP3_XNORcc 0x17
0dc1b72002-11-06Henrik Grubbström (Grubba) #define SPARC_OP3_ADD 0x00 #define SPARC_OP3_ADDcc 0x10 #define SPARC_OP3_ADDC 0x08 #define SPARC_OP3_ADDCcc 0x18
f5e8622002-11-07Henrik Grubbström (Grubba) #define SPARC_OP3_SUB 0x04 #define SPARC_OP3_SUBcc 0x14 #define SPARC_OP3_SUBC 0x0c #define SPARC_OP3_SUBCcc 0x1c
327cdd2002-11-07Henrik Grubbström (Grubba) #define SPARC_OP3_SLL 0x25 #define SPARC_OP3_SRL 0x26 #define SPARC_OP3_SRA 0x27 #define SPARC_OP3_RD 0x28
c0a5182002-11-10Henrik Grubbström (Grubba) #define SPARC_OP3_JMPL 0x38
ed16592002-11-09Henrik Grubbström (Grubba) #define SPARC_OP3_RETURN 0x39
f5e8622002-11-07Henrik Grubbström (Grubba) #define SPARC_OP3_SAVE 0x3c
c0a5182002-11-10Henrik Grubbström (Grubba) #define SPARC_OP3_RESTORE 0x3d
4f43322002-11-05Henrik Grubbström (Grubba) 
327cdd2002-11-07Henrik Grubbström (Grubba) #define SPARC_RD_REG_CCR 0x02 #define SPARC_RD_REG_PC 0x05
0dc1b72002-11-06Henrik Grubbström (Grubba) #define SPARC_ALU_OP(OP3, D, S1, S2, I) \
4f43322002-11-05Henrik Grubbström (Grubba)  add_to_program(0x80000000|((D)<<25)|((OP3)<<19)|((S1)<<14)|((I)<<13)| \
f5e8622002-11-07Henrik Grubbström (Grubba)  ((S2)&0x1fff))
4f43322002-11-05Henrik Grubbström (Grubba) 
aaf6d32002-11-08Henrik Grubbström (Grubba) #define SPARC_OP3_LDUW 0x00 #define SPARC_OP3_LDUH 0x02
58c2442005-06-17Henrik Grubbström (Grubba) #define SPARC_OP3_LDUB 0x01
aaf6d32002-11-08Henrik Grubbström (Grubba) #define SPARC_OP3_LDSW 0x08 #define SPARC_OP3_LDSH 0x0a
58c2442005-06-17Henrik Grubbström (Grubba) #define SPARC_OP3_LDSB 0x08 #define SPARC_OP3_LDX 0x0b
aaf6d32002-11-08Henrik Grubbström (Grubba) #define SPARC_OP3_STW 0x04 #define SPARC_OP3_STH 0x06
58c2442005-06-17Henrik Grubbström (Grubba) #define SPARC_OP3_STX 0x0e
aaf6d32002-11-08Henrik Grubbström (Grubba)  #define SPARC_MEM_OP(OP3, D, S1, S2, I) \ add_to_program(0xc0000000|((D)<<25)|((OP3)<<19)|((S1)<<14)|((I)<<13)| \ ((S2)&0x1fff))
112e5f2006-09-08Henrik Grubbström (Grubba) #define SPARC_ANDcc(D,S1,S2,I) SPARC_ALU_OP(SPARC_OP3_ANDcc, D, S1, S2, I)
0dc1b72002-11-06Henrik Grubbström (Grubba) #define SPARC_OR(D,S1,S2,I) SPARC_ALU_OP(SPARC_OP3_OR, D, S1, S2, I)
9b35842005-06-27Henrik Grubbström (Grubba) #define SPARC_XOR(D,S1,S2,I) SPARC_ALU_OP(SPARC_OP3_XOR, D, S1, S2, I)
4f43322002-11-05Henrik Grubbström (Grubba) 
0dc1b72002-11-06Henrik Grubbström (Grubba) #define SPARC_SRA(D,S1,S2,I) SPARC_ALU_OP(SPARC_OP3_SRA, D, S1, S2, I)
58c2442005-06-17Henrik Grubbström (Grubba) #define SPARC_SLL(D,S1,S2,I) SPARC_ALU_OP(SPARC_OP3_SLL, D, S1, S2, I)
0dc1b72002-11-06Henrik Grubbström (Grubba)  #define SPARC_ADD(D,S1,S2,I) SPARC_ALU_OP(SPARC_OP3_ADD, D, S1, S2, I)
aaf6d32002-11-08Henrik Grubbström (Grubba) #define SPARC_SUBcc(D,S1,S2,I) SPARC_ALU_OP(SPARC_OP3_SUBcc, D, S1, S2, I)
4f43322002-11-05Henrik Grubbström (Grubba) 
327cdd2002-11-07Henrik Grubbström (Grubba) #define SPARC_RD(D, RDREG) SPARC_ALU_OP(SPARC_OP3_RD, D, RDREG, 0, 0)
ed16592002-11-09Henrik Grubbström (Grubba) #define SPARC_RETURN(S1, S2, I) SPARC_ALU_OP(SPARC_OP3_RETURN, 0, S1, S2, I)
c0a5182002-11-10Henrik Grubbström (Grubba) #define SPARC_JMPL(D,S1,S2,I) SPARC_ALU_OP(SPARC_OP3_JMPL, D, S1, S2, I) #define SPARC_RET() SPARC_JMPL(SPARC_REG_G0, SPARC_REG_I7, 8, 1) #define SPARC_RESTORE(D,S1,S2,I) SPARC_ALU_OP(SPARC_OP3_RESTORE, D, S1, S2, I)
58c2442005-06-17Henrik Grubbström (Grubba) #define SPARC_LDX(D,S1,S2,I) SPARC_MEM_OP(SPARC_OP3_LDX, D, S1, S2, I)
aaf6d32002-11-08Henrik Grubbström (Grubba) #define SPARC_LDUW(D,S1,S2,I) SPARC_MEM_OP(SPARC_OP3_LDUW, D, S1, S2, I) #define SPARC_LDUH(D,S1,S2,I) SPARC_MEM_OP(SPARC_OP3_LDUH, D, S1, S2, I)
58c2442005-06-17Henrik Grubbström (Grubba) #define SPARC_STX(D,S1,S2,I) SPARC_MEM_OP(SPARC_OP3_STX, D, S1, S2, I)
aaf6d32002-11-08Henrik Grubbström (Grubba) #define SPARC_STW(D,S1,S2,I) SPARC_MEM_OP(SPARC_OP3_STW, D, S1, S2, I) #define SPARC_STH(D,S1,S2,I) SPARC_MEM_OP(SPARC_OP3_STH, D, S1, S2, I)
4f43322002-11-05Henrik Grubbström (Grubba) #define SPARC_SETHI(D, VAL) \ add_to_program(0x01000000|((D)<<25)|(((VAL)>>10)&0x3fffff))
112e5f2006-09-08Henrik Grubbström (Grubba) #define SPARC_NOOP() SPARC_SETHI(SPARC_REG_G0, 0) #define SPARC_BA(DISP22, A) \ add_to_program(0x10800000|((A)<<29)|(((DISP22)>>2)&0x1fffff))
4f43322002-11-05Henrik Grubbström (Grubba) 
aaf6d32002-11-08Henrik Grubbström (Grubba) #define SPARC_BE(DISP22, A) \ add_to_program(0x02800000|((A)<<29)|(((DISP22)>>2)&0x1fffff)) #define SPARC_BNE(DISP22, A) \ add_to_program(0x12800000|((A)<<29)|(((DISP22)>>2)&0x1fffff))
5e310c2002-11-11Henrik Grubbström (Grubba) #define SPARC_CALL(DISP30) \ add_to_program(0x40000000 | (((DISP30) >> 2) & 0x3fffffff))
4f43322002-11-05Henrik Grubbström (Grubba) #define SET_REG(REG, X) do { \
58c2442005-06-17Henrik Grubbström (Grubba)  INT64 val_ = X; \
4f43322002-11-05Henrik Grubbström (Grubba)  INT32 reg_ = REG; \
350ba02005-06-17Henrik Grubbström (Grubba)  /*fprintf(stderr, "SET_REG(0x%02x, %p)\n", reg_, (void *)val_);*/ \
4f43322002-11-05Henrik Grubbström (Grubba)  if ((-4096 <= val_) && (val_ <= 4095)) { \ /* or %g0, val_, reg */ \
40f4622002-11-05Henrik Grubbström (Grubba)  SPARC_OR(reg_, SPARC_REG_G0, val_, 1); \
9b35842005-06-27Henrik Grubbström (Grubba)  } else if (val_ < 0) { \ if ((-0x80000000LL <= val_)) { \ /* sethi %hi(~val_) */ \ SPARC_SETHI(reg_, ~val_); \ /* xor reg, %lo(val_)|0x1c00, reg */ \ SPARC_XOR(reg_, reg_, (val_ & 0x3ff)|0x1c00, 1); \ } else { \ /* FIXME: SPARC64 */ \ Pike_fatal("Value out of range: %p\n", (void *)val_); \
4f43322002-11-05Henrik Grubbström (Grubba)  } \
58c2442005-06-17Henrik Grubbström (Grubba)  } else { \
9b35842005-06-27Henrik Grubbström (Grubba)  if (val_ <= 0x7fffffffLL) { \ /* sethi %hi(val_), reg */ \ SPARC_SETHI(reg_, val_); \ if (val_ & 0x3ff) { \ /* or reg, %lo(val_), reg */ \ SPARC_OR(reg_, reg_, val_ & 0x3ff, 1); \ } \ } else if (!(val_>>34)) { \
58c2442005-06-17Henrik Grubbström (Grubba)  /* The top 30 bits are zero. */ \ SPARC_SETHI(reg_, val_>>2); \ SPARC_SLL(reg_, reg_, 2, 1); \ if (val_ & 0xfff) { \ SPARC_OR(reg_, reg_, val_ & 0xfff, 1); \ } \
9b35842005-06-27Henrik Grubbström (Grubba)  } else { \ /* FIXME: SPARC64 */ \
58c2442005-06-17Henrik Grubbström (Grubba)  Pike_fatal("Value out of range: %p\n", (void *)val_); \ } \
4f43322002-11-05Henrik Grubbström (Grubba)  } \ } while(0)
58c2442005-06-17Henrik Grubbström (Grubba)  /* FIXME: SPARC64 */
f1d1eb2001-07-20Henrik Grubbström (Grubba) #define ADD_CALL(X, DELAY_OK) do { \
58c2442005-06-17Henrik Grubbström (Grubba)  PIKE_OPCODE_T *ptr_ = (PIKE_OPCODE_T *)(X); \ ptrdiff_t delta_; \
dd6bca2001-07-20Henrik Grubbström (Grubba)  struct program *p_ = Pike_compiler->new_program; \ INT32 off_ = p_->num_program; \
f1d1eb2001-07-20Henrik Grubbström (Grubba)  /* noop */ \ INT32 delay_ = 0x01000000; \ \ if (DELAY_OK) { \ /* Move the previous opcode to the delay-slot. */ \ delay_ = p_->program[--off_]; \ } else { \ add_to_program(0); /* Placeholder... */ \ } \
350ba02005-06-17Henrik Grubbström (Grubba)  /*fprintf(stderr, "call %p (pc:%p)\n", ptr_, p_->program);*/ \
dd6bca2001-07-20Henrik Grubbström (Grubba)  /* call X */ \
58c2442005-06-17Henrik Grubbström (Grubba)  delta_ = ptr_ - (p_->program + off_); \ if ((-0x20000000L <= delta_) && (delta_ <= 0x1fffffff)) { \ p_->program[off_] = 0x40000000 | (delta_ & 0x3fffffff); \ add_to_relocations(off_); \ } else { \ /* NOTE: Assumes top 30 bits are zero! */ \ /* sethi %hi(ptr_>>2), %o7 */ \ p_->program[off_] = \ 0x01000000|(SPARC_REG_O7<<25)|((((size_t)ptr_)>>12)&0x3fffff); \ /* sll %o7, 2, %o7 */ \ SPARC_SLL(SPARC_REG_O7, SPARC_REG_O7, 2, 1); \ /* call %o7 + %lo(ptr_) */ \ SPARC_JMPL(SPARC_REG_O7, SPARC_REG_O7, ((size_t)ptr_)&0xfff, 1); \ } \
f1d1eb2001-07-20Henrik Grubbström (Grubba)  add_to_program(delay_); \
327cdd2002-11-07Henrik Grubbström (Grubba)  sparc_last_pc = off_; /* Value in %o7. */ \ sparc_codegen_state |= SPARC_CODEGEN_PC_IS_SET; \
0dc1b72002-11-06Henrik Grubbström (Grubba)  } while(0) /* * Register conventions: *
aaf6d32002-11-08Henrik Grubbström (Grubba)  * I0 Scratch *
0dc1b72002-11-06Henrik Grubbström (Grubba)  * I6 Frame pointer * I7 Return address *
aaf6d32002-11-08Henrik Grubbström (Grubba)  * L0 &Pike_interpreter * L1 Pike_fp
2315a62003-09-23Henrik Grubbström (Grubba)  * L7 &d_flag
0dc1b72002-11-06Henrik Grubbström (Grubba)  * * O6 Stack Pointer * O7 Program Counter * */
aaf6d32002-11-08Henrik Grubbström (Grubba) #define SPARC_REG_PIKE_IP SPARC_REG_L0 #define SPARC_REG_PIKE_FP SPARC_REG_L1 #define SPARC_REG_PIKE_SP SPARC_REG_L2 #define SPARC_REG_PIKE_MARK_SP SPARC_REG_L3
01de412002-11-08Henrik Grubbström (Grubba) #define SPARC_REG_PIKE_OBJ SPARC_REG_L4
2315a62003-09-23Henrik Grubbström (Grubba) #define SPARC_REG_PIKE_DEBUG SPARC_REG_L7
0dc1b72002-11-06Henrik Grubbström (Grubba) #define SPARC_REG_SP SPARC_REG_O6 #define SPARC_REG_PC SPARC_REG_O7 /* * Code generator state. */ unsigned INT32 sparc_codegen_state = 0;
6a2a6d2005-06-23Henrik Grubbström (Grubba) static int sparc_pike_sp_bias = 0;
58c2442005-06-17Henrik Grubbström (Grubba) ptrdiff_t sparc_last_pc = 0; #ifdef PIKE_BYTECODE_SPARC64 #define PIKE_LDPTR SPARC_LDX #define PIKE_STPTR SPARC_STX #else /* !PIKE_BYTECODE_SPARC64 */ #define PIKE_LDPTR SPARC_LDUW #define PIKE_STPTR SPARC_STW #endif /* PIKE_BYTECODE_SPARC64 */
0dc1b72002-11-06Henrik Grubbström (Grubba) 
aaf6d32002-11-08Henrik Grubbström (Grubba) #define LOAD_PIKE_INTERPRETER() do { \ if (!(sparc_codegen_state & SPARC_CODEGEN_IP_IS_SET)) { \ SET_REG(SPARC_REG_PIKE_IP, \
58c2442005-06-17Henrik Grubbström (Grubba)  ((ptrdiff_t)(&Pike_interpreter))); \
aaf6d32002-11-08Henrik Grubbström (Grubba)  sparc_codegen_state |= SPARC_CODEGEN_IP_IS_SET; \
0dc1b72002-11-06Henrik Grubbström (Grubba)  } \
dd6bca2001-07-20Henrik Grubbström (Grubba)  } while(0)
aaf6d32002-11-08Henrik Grubbström (Grubba) #define LOAD_PIKE_FP() do { \ if (!(sparc_codegen_state & SPARC_CODEGEN_FP_IS_SET)) { \ LOAD_PIKE_INTERPRETER(); \ /* lduw [ %ip, %offset(Pike_interpreter, frame_pointer) ], %l1 */ \
58c2442005-06-17Henrik Grubbström (Grubba)  PIKE_LDPTR(SPARC_REG_PIKE_FP, SPARC_REG_PIKE_IP, \
aaf6d32002-11-08Henrik Grubbström (Grubba)  OFFSETOF(Pike_interpreter, frame_pointer), 1); \ sparc_codegen_state |= SPARC_CODEGEN_FP_IS_SET; \ } \ } while(0) #define LOAD_PIKE_SP() do { \ if (!(sparc_codegen_state & SPARC_CODEGEN_SP_IS_SET)) { \ LOAD_PIKE_INTERPRETER(); \ /* lduw [ %ip, %offset(Pike_interpreter, stack_pointer) ], %l2 */ \
58c2442005-06-17Henrik Grubbström (Grubba)  PIKE_LDPTR(SPARC_REG_PIKE_SP, SPARC_REG_PIKE_IP, \
aaf6d32002-11-08Henrik Grubbström (Grubba)  OFFSETOF(Pike_interpreter, stack_pointer), 1); \ sparc_codegen_state |= SPARC_CODEGEN_SP_IS_SET; \
6a2a6d2005-06-23Henrik Grubbström (Grubba)  sparc_pike_sp_bias = 0; \ } else if (sparc_pike_sp_bias > 0xf00) { \ /* Make sure there's always space for at least 256 bytes. */ \ SPARC_ADD(SPARC_REG_PIKE_SP, SPARC_REG_PIKE_SP, \ sparc_pike_sp_bias, 1); \ sparc_pike_sp_bias = 0; \ sparc_codegen_state |= SPARC_CODEGEN_SP_NEEDS_STORE; \
aaf6d32002-11-08Henrik Grubbström (Grubba)  } \ } while(0) #define LOAD_PIKE_MARK_SP() do { \ if (!(sparc_codegen_state & SPARC_CODEGEN_MARK_SP_IS_SET)) { \ LOAD_PIKE_INTERPRETER(); \ /* lduw [ %ip, %offset(Pike_interpreter, mark_stack_pointer) ], %l2 */ \
58c2442005-06-17Henrik Grubbström (Grubba)  PIKE_LDPTR(SPARC_REG_PIKE_MARK_SP, SPARC_REG_PIKE_IP, \
aaf6d32002-11-08Henrik Grubbström (Grubba)  OFFSETOF(Pike_interpreter, mark_stack_pointer), 1); \ sparc_codegen_state |= SPARC_CODEGEN_MARK_SP_IS_SET; \ } \ } while(0) #define SPARC_FLUSH_UNSTORED() do { \
6a2a6d2005-06-23Henrik Grubbström (Grubba)  if (sparc_pike_sp_bias) { \ SPARC_ADD(SPARC_REG_PIKE_SP, SPARC_REG_PIKE_SP, \ sparc_pike_sp_bias, 1); \ sparc_pike_sp_bias = 0; \ sparc_codegen_state |= SPARC_CODEGEN_SP_NEEDS_STORE; \ } \
aaf6d32002-11-08Henrik Grubbström (Grubba)  if (sparc_codegen_state & SPARC_CODEGEN_MARK_SP_NEEDS_STORE) { \ /* stw %pike_mark_sp, [ %ip, %offset(Pike_interpreter, mark_stack_pointer) ] */ \
58c2442005-06-17Henrik Grubbström (Grubba)  PIKE_STPTR(SPARC_REG_PIKE_MARK_SP, SPARC_REG_PIKE_IP, \ OFFSETOF(Pike_interpreter, mark_stack_pointer), 1); \
aaf6d32002-11-08Henrik Grubbström (Grubba)  sparc_codegen_state &= ~SPARC_CODEGEN_MARK_SP_NEEDS_STORE; \ } \ if (sparc_codegen_state & SPARC_CODEGEN_SP_NEEDS_STORE) { \ /* stw %pike_sp, [ %ip, %offset(Pike_interpreter, stack_pointer) ] */ \
58c2442005-06-17Henrik Grubbström (Grubba)  PIKE_STPTR(SPARC_REG_PIKE_SP, SPARC_REG_PIKE_IP, \ OFFSETOF(Pike_interpreter, stack_pointer), 1); \
aaf6d32002-11-08Henrik Grubbström (Grubba)  sparc_codegen_state &= ~SPARC_CODEGEN_SP_NEEDS_STORE; \ } \ } while(0) #define SPARC_UNLOAD_CACHED() \ (sparc_codegen_state &= ~(SPARC_CODEGEN_FP_IS_SET| \ SPARC_CODEGEN_SP_IS_SET| \ SPARC_CODEGEN_MARK_SP_IS_SET))
ebba5c2002-11-07Henrik Grubbström (Grubba) 
a970e52002-11-08Henrik Grubbström (Grubba) void sparc_flush_codegen_state(void) { SPARC_FLUSH_UNSTORED(); sparc_codegen_state = 0; } #define ADJUST_PIKE_PC(NEW_PC) do { \ sparc_last_pc = NEW_PC; \ sparc_codegen_state |= SPARC_CODEGEN_PC_IS_SET; \ } while(0)
8c39e22005-06-23Henrik Grubbström (Grubba) #if 0 static void sparc_trace_fun(PIKE_OPCODE_T *pc) { struct program *prog = NULL; if (Pike_fp->current_object && (prog = Pike_fp->current_object->prog)) { struct pike_string *fname; INT32 lineno; if (fname = low_get_line(pc + 4, prog, &lineno)) { fprintf(stderr, "TRACE: %p: %s:%d\n", pc, fname->str, lineno); free_string(fname); return; } } fprintf(stderr, "TRACE: %p: %p, %p\n", pc, Pike_fp->current_object, prog); } #endif /* 0 */
4f43322002-11-05Henrik Grubbström (Grubba) /* * Allocate a stack frame. * * Note that the prologue size must be constant. */ void sparc_ins_entry(void) {
58c2442005-06-17Henrik Grubbström (Grubba) #ifdef PIKE_BYTECODE_SPARC64 /* save %sp, -224, %sp */ add_to_program(0x81e02000|(SPARC_REG_SP<<25)|
8c39e22005-06-23Henrik Grubbström (Grubba)  (SPARC_REG_SP<<14)|((-176)&0x1fff));
58c2442005-06-17Henrik Grubbström (Grubba) #else /* !PIKE_BYTECODE_SPARC64 */
4f43322002-11-05Henrik Grubbström (Grubba)  /* save %sp, -112, %sp */
0dc1b72002-11-06Henrik Grubbström (Grubba)  add_to_program(0x81e02000|(SPARC_REG_SP<<25)| (SPARC_REG_SP<<14)|((-112)&0x1fff));
58c2442005-06-17Henrik Grubbström (Grubba) #endif /* PIKE_BYTECODE_SPARC64 */
8c39e22005-06-23Henrik Grubbström (Grubba) #if 0 SPARC_OR(SPARC_REG_O0, SPARC_REG_G0, SPARC_REG_O7, 0); ADD_CALL(sparc_trace_fun, 1); #endif /* 0 */
b3618b2002-11-06Henrik Grubbström (Grubba)  FLUSH_CODE_GENERATOR_STATE();
4f43322002-11-05Henrik Grubbström (Grubba) }
8d0cf12002-11-05Henrik Grubbström (Grubba) /* Update Pike_fp->pc */
4f43322002-11-05Henrik Grubbström (Grubba) void sparc_update_pc(void) {
ed16592002-11-09Henrik Grubbström (Grubba)  LOAD_PIKE_FP();
58c2442005-06-17Henrik Grubbström (Grubba) #ifdef PIKE_BYTECODE_SPARC64
239d472002-11-11Henrik Grubbström (Grubba)  /* The ASR registers are implementation specific in Sparc V7 and V8. */
de35bc2005-06-21Henrik Grubbström (Grubba)  /* rd %pc, %o7 */ SPARC_RD(SPARC_REG_O7, SPARC_RD_REG_PC);
239d472002-11-11Henrik Grubbström (Grubba) #else /* !0 */ /* call .+8 */ SPARC_CALL(8); /* The new %o7 is available in the delay slot. */ #endif /* 0 */
de35bc2005-06-21Henrik Grubbström (Grubba)  /* stw %o7, [ %pike_fp + pc ] */ PIKE_STPTR(SPARC_REG_O7, SPARC_REG_PIKE_FP, OFFSETOF(pike_frame, pc), 1);
4f43322002-11-05Henrik Grubbström (Grubba) }
aaf6d32002-11-08Henrik Grubbström (Grubba) /* * Opcode implementations. */
4f43322002-11-05Henrik Grubbström (Grubba) 
aaf6d32002-11-08Henrik Grubbström (Grubba) #define MAKE_TYPE_WORD(TYPE, SUB_TYPE) (((TYPE) << 16)|(SUB_TYPE)) static void sparc_incr_mark_sp(int delta) { LOAD_PIKE_MARK_SP(); /* add %pike_mark_sp, %pike_mark_sp, 4 * delta */
58c2442005-06-17Henrik Grubbström (Grubba)  SPARC_ADD(SPARC_REG_PIKE_MARK_SP, SPARC_REG_PIKE_MARK_SP, sizeof(void *)*delta, 1);
aaf6d32002-11-08Henrik Grubbström (Grubba)  sparc_codegen_state |= SPARC_CODEGEN_MARK_SP_NEEDS_STORE; }
6a2a6d2005-06-23Henrik Grubbström (Grubba) static void sparc_mark(ptrdiff_t off)
aaf6d32002-11-08Henrik Grubbström (Grubba) { LOAD_PIKE_SP(); LOAD_PIKE_MARK_SP();
6a2a6d2005-06-23Henrik Grubbström (Grubba)  off *= sizeof(struct svalue); off += sparc_pike_sp_bias;
aaf6d32002-11-08Henrik Grubbström (Grubba)  if (off) { if ((-4096 <= off) && (off < 4096)) { /* add %i0, %pike_sp, off */ SPARC_ADD(SPARC_REG_I0, SPARC_REG_PIKE_SP, off, 1); } else { SET_REG(SPARC_REG_I0, off); /* add %i0, %pike_sp, %i0 */ SPARC_ADD(SPARC_REG_I0, SPARC_REG_PIKE_SP, SPARC_REG_I0, 0); } /* stw %i0, [ %pike_mark_sp, %g0 ] */
58c2442005-06-17Henrik Grubbström (Grubba)  PIKE_STPTR(SPARC_REG_I0, SPARC_REG_PIKE_MARK_SP, SPARC_REG_G0, 0);
aaf6d32002-11-08Henrik Grubbström (Grubba)  } else { /* stw %pike_sp, [ %pike_mark_sp, %g0 ] */
58c2442005-06-17Henrik Grubbström (Grubba)  PIKE_STPTR(SPARC_REG_PIKE_SP, SPARC_REG_PIKE_MARK_SP, SPARC_REG_G0, 0);
aaf6d32002-11-08Henrik Grubbström (Grubba)  } sparc_incr_mark_sp(1); }
8c39e22005-06-23Henrik Grubbström (Grubba) static void sparc_push_int(INT_TYPE x, int sub_type)
aaf6d32002-11-08Henrik Grubbström (Grubba) { INT32 type_word = MAKE_TYPE_WORD(PIKE_T_INT, sub_type);
58c2442005-06-17Henrik Grubbström (Grubba)  int reg = SPARC_REG_G0;
aaf6d32002-11-08Henrik Grubbström (Grubba)  LOAD_PIKE_SP();
8c39e22005-06-23Henrik Grubbström (Grubba) #ifdef PIKE_DEBUG
aaf6d32002-11-08Henrik Grubbström (Grubba)  if (sizeof(struct svalue) > 8) { size_t e; for (e = 4; e < sizeof(struct svalue); e += 4) {
58c2442005-06-17Henrik Grubbström (Grubba)  /* Pad until we reach the anything field. */
aaf6d32002-11-08Henrik Grubbström (Grubba)  if (e == OFFSETOF(svalue, u.integer)) continue; /* stw %g0, [ %pike_sp, e ] */
6a2a6d2005-06-23Henrik Grubbström (Grubba)  SPARC_STW(SPARC_REG_G0, SPARC_REG_PIKE_SP, sparc_pike_sp_bias + e, 1);
aaf6d32002-11-08Henrik Grubbström (Grubba)  } }
8c39e22005-06-23Henrik Grubbström (Grubba) #endif /* PIKE_DEBUG */
aaf6d32002-11-08Henrik Grubbström (Grubba)  if (x) { SET_REG(SPARC_REG_I1, x);
58c2442005-06-17Henrik Grubbström (Grubba)  reg = SPARC_REG_I1; } if (sizeof(INT_TYPE) == 4) {
6a2a6d2005-06-23Henrik Grubbström (Grubba)  SPARC_STW(reg, SPARC_REG_PIKE_SP, sparc_pike_sp_bias + OFFSETOF(svalue, u.integer), 1);
aaf6d32002-11-08Henrik Grubbström (Grubba)  } else {
6a2a6d2005-06-23Henrik Grubbström (Grubba)  SPARC_STX(reg, SPARC_REG_PIKE_SP, sparc_pike_sp_bias + OFFSETOF(svalue, u.integer), 1);
aaf6d32002-11-08Henrik Grubbström (Grubba)  } if (x != type_word) {
01de412002-11-08Henrik Grubbström (Grubba)  SET_REG(SPARC_REG_I1, type_word);
aaf6d32002-11-08Henrik Grubbström (Grubba)  } /* This is safe since type_word is never zero. */
01de412002-11-08Henrik Grubbström (Grubba)  /* stw %i1, [ %pike_sp ] */
6a2a6d2005-06-23Henrik Grubbström (Grubba)  SPARC_STW(SPARC_REG_I1, SPARC_REG_PIKE_SP, sparc_pike_sp_bias, 1); sparc_pike_sp_bias += sizeof(struct svalue);
aaf6d32002-11-08Henrik Grubbström (Grubba)  sparc_codegen_state |= SPARC_CODEGEN_SP_NEEDS_STORE; } static void sparc_clear_string_subtype(void) { LOAD_PIKE_SP(); /* lduh [ %pike_sp, %g0 ], %i0 */
6a2a6d2005-06-23Henrik Grubbström (Grubba)  SPARC_LDUH(SPARC_REG_I0, SPARC_REG_PIKE_SP, sparc_pike_sp_bias + OFFSETOF(svalue, type), 1);
aaf6d32002-11-08Henrik Grubbström (Grubba)  /* subcc %g0, %i0, 8 */ SPARC_SUBcc(SPARC_REG_G0, SPARC_REG_I0, PIKE_T_INT, 1); /* be,a .+8 */ SPARC_BE(8, 1); /* sth %g0, [ %pike_sp, 2 ] */
6a2a6d2005-06-23Henrik Grubbström (Grubba)  SPARC_STH(SPARC_REG_G0, SPARC_REG_PIKE_SP, sparc_pike_sp_bias + OFFSETOF(svalue, subtype), 1);
aaf6d32002-11-08Henrik Grubbström (Grubba) }
01de412002-11-08Henrik Grubbström (Grubba) static void sparc_push_lfun(unsigned int no) { LOAD_PIKE_FP(); LOAD_PIKE_SP(); /* lduw [ %pike_fp, %offset(pike_frame, current_object) ], %pike_obj */
58c2442005-06-17Henrik Grubbström (Grubba)  PIKE_LDPTR(SPARC_REG_PIKE_OBJ, SPARC_REG_PIKE_FP,
01de412002-11-08Henrik Grubbström (Grubba)  OFFSETOF(pike_frame, current_object), 1); /* stw %pike_obj, [ %pike_sp, %offset(svalue, u.object) ] */
58c2442005-06-17Henrik Grubbström (Grubba)  PIKE_STPTR(SPARC_REG_PIKE_OBJ, SPARC_REG_PIKE_SP,
6a2a6d2005-06-23Henrik Grubbström (Grubba)  sparc_pike_sp_bias + OFFSETOF(svalue, u.object), 1);
01de412002-11-08Henrik Grubbström (Grubba)  /* lduw [ %pike_obj, %offset(object, refs) ], %i0 */ SPARC_LDUW(SPARC_REG_I0, SPARC_REG_PIKE_OBJ, OFFSETOF(object, refs), 1); /* add %i0, 1, %i0 */ SPARC_ADD(SPARC_REG_I0, SPARC_REG_I0, 1, 1);
78f61d2008-02-28Henrik Grubbström (Grubba)  /* lduw [ %pike_fp, %offset(pike_frame, context) ], %i1 */
b3575e2008-02-28Henrik Grubbström (Grubba)  PIKE_LDPTR(SPARC_REG_PIKE_OBJ, SPARC_REG_I1,
78f61d2008-02-28Henrik Grubbström (Grubba)  OFFSETOF(pike_frame, context), 1);
01de412002-11-08Henrik Grubbström (Grubba)  /* stw %i0, [ %pike_obj, %offset(object, refs) ] */ SPARC_STW(SPARC_REG_I0, SPARC_REG_PIKE_OBJ, OFFSETOF(object, refs), 1);
b3575e2008-02-28Henrik Grubbström (Grubba)  /* lduh [ %i1, %offset(inherit, identifier_level ], %i1 */
78f61d2008-02-28Henrik Grubbström (Grubba)  SPARC_LDUH(SPARC_REG_I1, SPARC_REG_I1, OFFSETOF(inherit, identifier_level), 1);
01de412002-11-08Henrik Grubbström (Grubba)  SET_REG(SPARC_REG_I2, (no & 0xffff) | (PIKE_T_FUNCTION << 16)); /* add %i1, %i2, %i1 */ SPARC_ADD(SPARC_REG_I1, SPARC_REG_I1, SPARC_REG_I2, 0); /* stw %i1, [ %pike_sp, %g0 ] */
6a2a6d2005-06-23Henrik Grubbström (Grubba)  SPARC_STW(SPARC_REG_I1, SPARC_REG_PIKE_SP, sparc_pike_sp_bias, 1); sparc_pike_sp_bias += sizeof(struct svalue);
01de412002-11-08Henrik Grubbström (Grubba)  sparc_codegen_state |= SPARC_CODEGEN_SP_NEEDS_STORE; } void sparc_local_lvalue(unsigned int no) { LOAD_PIKE_SP(); LOAD_PIKE_FP();
401ef22003-02-16Martin Stjernholm  SET_REG(SPARC_REG_I0, T_SVALUE_PTR);
01de412002-11-08Henrik Grubbström (Grubba)  /* sth %i0, [ %pike_sp, %g0 ] */
6a2a6d2005-06-23Henrik Grubbström (Grubba)  SPARC_STH(SPARC_REG_I0, SPARC_REG_PIKE_SP, sparc_pike_sp_bias, 1);
01de412002-11-08Henrik Grubbström (Grubba)  SET_REG(SPARC_REG_I0, T_VOID);
ed16592002-11-09Henrik Grubbström (Grubba)  no *= sizeof(struct svalue); if (no < 4096) { /* lduw [ %pike_fp, %offset(pike_frame, locals) ], %i2 */
58c2442005-06-17Henrik Grubbström (Grubba)  PIKE_LDPTR(SPARC_REG_I2, SPARC_REG_PIKE_FP,
ed16592002-11-09Henrik Grubbström (Grubba)  OFFSETOF(pike_frame, locals), 1); /* add %i2, no * sizeof(struct svalue), %i2 */ SPARC_ADD(SPARC_REG_I2, SPARC_REG_I2, no, 1); } else { SET_REG(SPARC_REG_I1, no); /* lduw [ %pike_fp, %offset(pike_frame, locals) ], %i2 */
58c2442005-06-17Henrik Grubbström (Grubba)  PIKE_LDPTR(SPARC_REG_I2, SPARC_REG_PIKE_FP,
ed16592002-11-09Henrik Grubbström (Grubba)  OFFSETOF(pike_frame, locals), 1); /* add %i2, %i1, %i2 */ SPARC_ADD(SPARC_REG_I2, SPARC_REG_I2, SPARC_REG_I1, 0); }
01de412002-11-08Henrik Grubbström (Grubba)  /* stw %i2, [ %pike_sp, %offset(svalue, u.lval) ] */
58c2442005-06-17Henrik Grubbström (Grubba)  PIKE_STPTR(SPARC_REG_I2, SPARC_REG_PIKE_SP,
6a2a6d2005-06-23Henrik Grubbström (Grubba)  sparc_pike_sp_bias + OFFSETOF(svalue, u.lval), 1); sparc_pike_sp_bias += sizeof(struct svalue) * 2;
01de412002-11-08Henrik Grubbström (Grubba)  /* sth %i0, [ %pike_sp , -sizeof(struct svalue) ] */
6a2a6d2005-06-23Henrik Grubbström (Grubba)  SPARC_STH(SPARC_REG_I0, SPARC_REG_PIKE_SP, sparc_pike_sp_bias - sizeof(struct svalue), 1);
01de412002-11-08Henrik Grubbström (Grubba)  sparc_codegen_state |= SPARC_CODEGEN_SP_NEEDS_STORE; }
aaf6d32002-11-08Henrik Grubbström (Grubba) /* * */
4f43322002-11-05Henrik Grubbström (Grubba) 
2315a62003-09-23Henrik Grubbström (Grubba) #ifdef PIKE_DEBUG void sparc_debug_check_registers(int state, struct Pike_interpreter *cached_ip, struct pike_frame *cached_fp, struct svalue *cached_sp, struct svalue **cached_mark_sp) { if (((state & SPARC_CODEGEN_IP_IS_SET) && (cached_ip != &Pike_interpreter)) || ((state & SPARC_CODEGEN_FP_IS_SET) && (cached_fp != Pike_interpreter.frame_pointer)) || ((state & SPARC_CODEGEN_SP_IS_SET) && (cached_sp != Pike_interpreter.stack_pointer)) || ((state & SPARC_CODEGEN_MARK_SP_IS_SET) && (cached_mark_sp != Pike_interpreter.mark_stack_pointer))) { Pike_fatal("Bad machine code cache key (0x%04x):\n" "Cached: ip:0x%08x, fp:0x%08x, sp:0x%08x, m_sp:0x%08x\n" " Real: ip:0x%08x, fp:0x%08x, sp:0x%08x, m_sp:0x%08x\n", state, (INT32)cached_ip, (INT32)cached_fp, (INT32)cached_sp, (INT32)cached_mark_sp, (INT32)&Pike_interpreter, (INT32)Pike_interpreter.frame_pointer, (INT32)Pike_interpreter.stack_pointer, (INT32)Pike_interpreter.mark_stack_pointer); } } static void ins_sparc_debug() { int state = sparc_codegen_state; if (state & SPARC_CODEGEN_SP_NEEDS_STORE) { state &= ~SPARC_CODEGEN_SP_IS_SET; } if (state & SPARC_CODEGEN_MARK_SP_NEEDS_STORE) { state &= ~SPARC_CODEGEN_MARK_SP_IS_SET; } if (state & (SPARC_CODEGEN_FP_IS_SET|SPARC_CODEGEN_SP_IS_SET| SPARC_CODEGEN_IP_IS_SET|SPARC_CODEGEN_MARK_SP_IS_SET)) {
58c2442005-06-17Henrik Grubbström (Grubba)  SET_REG(SPARC_REG_PIKE_DEBUG, ((ptrdiff_t)(&d_flag)));
2315a62003-09-23Henrik Grubbström (Grubba)  SPARC_LDUW(SPARC_REG_PIKE_DEBUG, SPARC_REG_PIKE_DEBUG, SPARC_REG_G0, 0); SPARC_SUBcc(SPARC_REG_G0, SPARC_REG_PIKE_DEBUG, SPARC_REG_G0, 0); SET_REG(SPARC_REG_O0, state);
58c2442005-06-17Henrik Grubbström (Grubba) #ifdef PIKE_BYTECODE_SPARC64 SPARC_BE(8*4, 0); SPARC_OR(SPARC_REG_O1, SPARC_REG_PIKE_IP, SPARC_REG_G0, 0); SPARC_SETHI(SPARC_REG_O7, ((ptrdiff_t)sparc_debug_check_registers)>>2); SPARC_OR(SPARC_REG_O2, SPARC_REG_PIKE_FP, SPARC_REG_G0, 0); SPARC_SLL(SPARC_REG_O7, SPARC_REG_O7, 2, 1);
6a2a6d2005-06-23Henrik Grubbström (Grubba)  SPARC_ADD(SPARC_REG_O3, SPARC_REG_PIKE_SP, sparc_pike_sp_bias, 1);
58c2442005-06-17Henrik Grubbström (Grubba)  SPARC_JMPL(SPARC_REG_O7, SPARC_REG_O7, ((ptrdiff_t)sparc_debug_check_registers) & 0xfff, 1); SPARC_OR(SPARC_REG_O4, SPARC_REG_PIKE_MARK_SP, SPARC_REG_G0, 0); #else /* !PIKE_BYTECODE_SPARC64 */ /* NOTE: Assumes ADD_CALL below is a single instruction. */
2315a62003-09-23Henrik Grubbström (Grubba)  SPARC_BE(6*4, 0);
58c2442005-06-17Henrik Grubbström (Grubba)  SPARC_OR(SPARC_REG_O1, SPARC_REG_PIKE_IP, SPARC_REG_G0, 0); SPARC_OR(SPARC_REG_O2, SPARC_REG_PIKE_FP, SPARC_REG_G0, 0);
6a2a6d2005-06-23Henrik Grubbström (Grubba)  SPARC_ADD(SPARC_REG_O3, SPARC_REG_PIKE_SP, sparc_pike_sp_bias, 1);
58c2442005-06-17Henrik Grubbström (Grubba)  SPARC_OR(SPARC_REG_O4, SPARC_REG_PIKE_MARK_SP, SPARC_REG_G0, 0);
2315a62003-09-23Henrik Grubbström (Grubba)  ADD_CALL(sparc_debug_check_registers, 1);
58c2442005-06-17Henrik Grubbström (Grubba) #endif /* PIKE_BYTECODE_SPARC64 */
2315a62003-09-23Henrik Grubbström (Grubba)  } } #else /* !PIKE_DEBUG */ #define ins_sparc_debug() #endif /* PIKE_DEBUG */
9d98382003-08-15Henrik Grubbström (Grubba) static void low_ins_call(void *addr, int delay_ok, int i_flags)
01de412002-11-08Henrik Grubbström (Grubba) { SPARC_FLUSH_UNSTORED(); { static int last_prog_id=-1; static size_t last_num_linenumbers=(size_t)~0; if(last_prog_id != Pike_compiler->new_program->id || last_num_linenumbers != Pike_compiler->new_program->num_linenumbers) { last_prog_id=Pike_compiler->new_program->id; last_num_linenumbers = Pike_compiler->new_program->num_linenumbers; LOAD_PIKE_FP(); /* Note: We fill the delay slot with the following opcode. * This works since the new %o7 is available immediately. * (Sparc Architecture Manual V9 p149.) */ /* stw %o7, [ %pike_fp, %offsetof(pike_frame, pc) ] */
de35bc2005-06-21Henrik Grubbström (Grubba)  PIKE_STPTR(SPARC_REG_O7, SPARC_REG_PIKE_FP, OFFSETOF(pike_frame, pc), 1);
01de412002-11-08Henrik Grubbström (Grubba)  delay_ok = 1; } } ADD_CALL(addr, delay_ok);
9d98382003-08-15Henrik Grubbström (Grubba) #if 1 /* Invalidate cached values if needed. */ if (i_flags & (I_UPDATE_SP|I_UPDATE_M_SP|I_UPDATE_FP)) { if (i_flags & I_UPDATE_SP) { sparc_codegen_state &= ~SPARC_CODEGEN_SP_IS_SET; } if (i_flags & I_UPDATE_M_SP) { sparc_codegen_state &= ~SPARC_CODEGEN_MARK_SP_IS_SET; } if (i_flags & I_UPDATE_FP) { sparc_codegen_state &= ~SPARC_CODEGEN_FP_IS_SET; } } #else /* !1 */
01de412002-11-08Henrik Grubbström (Grubba)  /* This is probably only needed for some instructions, but... */ SPARC_UNLOAD_CACHED();
9d98382003-08-15Henrik Grubbström (Grubba) #endif /* 1 */
01de412002-11-08Henrik Grubbström (Grubba) }
f1d1eb2001-07-20Henrik Grubbström (Grubba) static void low_ins_f_byte(unsigned int b, int delay_ok)
dd6bca2001-07-20Henrik Grubbström (Grubba) {
11ed4b2001-07-24Henrik Grubbström (Grubba)  void *addr;
fc31002001-07-24Henrik Grubbström (Grubba) 
dd6bca2001-07-20Henrik Grubbström (Grubba)  b-=F_OFFSET; #ifdef PIKE_DEBUG if(b>255) Pike_error("Instruction too big %d\n",b); #endif
11ed4b2001-07-24Henrik Grubbström (Grubba)  addr = instrs[b].address;
9a928d2002-05-10Martin Stjernholm #ifdef PIKE_DEBUG if (d_flag < 3) #endif
fc31002001-07-24Henrik Grubbström (Grubba)  /* This is not very pretty */ switch(b) {
aaf6d32002-11-08Henrik Grubbström (Grubba)  case F_MARK2 - F_OFFSET: sparc_mark(0); /* FALL_THROUGH */ case F_SYNCH_MARK - F_OFFSET: case F_MARK - F_OFFSET: sparc_mark(0); return;
c0a5182002-11-10Henrik Grubbström (Grubba) 
aaf6d32002-11-08Henrik Grubbström (Grubba)  case F_POP_MARK - F_OFFSET: sparc_incr_mark_sp(-1); return; case F_UNDEFINED - F_OFFSET: sparc_push_int(0, 1); return;
c0a5182002-11-10Henrik Grubbström (Grubba) 
aaf6d32002-11-08Henrik Grubbström (Grubba)  case F_MARK_AND_CONST0 - F_OFFSET: sparc_mark(0);
c0a5182002-11-10Henrik Grubbström (Grubba)  /* FALL_THROUGH */ case F_CONST0 - F_OFFSET:
aaf6d32002-11-08Henrik Grubbström (Grubba)  sparc_push_int(0, 0); return;
c0a5182002-11-10Henrik Grubbström (Grubba) 
aaf6d32002-11-08Henrik Grubbström (Grubba)  case F_MARK_AND_CONST1 - F_OFFSET: sparc_mark(0);
c0a5182002-11-10Henrik Grubbström (Grubba)  /* FALL_THROUGH */ case F_CONST1 - F_OFFSET:
aaf6d32002-11-08Henrik Grubbström (Grubba)  sparc_push_int(1, 0); return;
c0a5182002-11-10Henrik Grubbström (Grubba) 
aaf6d32002-11-08Henrik Grubbström (Grubba)  case F_CONST_1 - F_OFFSET: sparc_push_int(-1, 0); return; case F_BIGNUM - F_OFFSET: sparc_push_int(0x7fffffff, 0); return;
01de412002-11-08Henrik Grubbström (Grubba) 
ed16592002-11-09Henrik Grubbström (Grubba)  case F_EXIT_CATCH - F_OFFSET: sparc_push_int(0, 1);
61134e2006-03-07Henrik Grubbström (Grubba)  addr = instrs[b = F_ESCAPE_CATCH-F_OFFSET].address; break;
ed16592002-11-09Henrik Grubbström (Grubba) 
fc31002001-07-24Henrik Grubbström (Grubba)  case F_MAKE_ITERATOR - F_OFFSET: { SET_REG(SPARC_REG_O0, 1); delay_ok = 1;
0dd1bc2003-04-18Martin Stjernholm  addr = (void *)f_get_iterator;
fc31002001-07-24Henrik Grubbström (Grubba)  } break;
f64f7e2002-11-08Henrik Grubbström (Grubba) 
fc31002001-07-24Henrik Grubbström (Grubba)  case F_ADD - F_OFFSET: SET_REG(SPARC_REG_O0, 2); delay_ok = 1; addr = (void *)f_add; break;
01de412002-11-08Henrik Grubbström (Grubba)  /* F_ZERO_TYPE? */
f5e8622002-11-07Henrik Grubbström (Grubba)  }
9d98382003-08-15Henrik Grubbström (Grubba)  low_ins_call(addr, delay_ok, instrs[b].flags);
f1d1eb2001-07-20Henrik Grubbström (Grubba) } void ins_f_byte(unsigned int opcode) {
2315a62003-09-23Henrik Grubbström (Grubba)  ins_sparc_debug();
f1d1eb2001-07-20Henrik Grubbström (Grubba)  low_ins_f_byte(opcode, 0);
dd6bca2001-07-20Henrik Grubbström (Grubba) }
112e5f2006-09-08Henrik Grubbström (Grubba) void ins_f_byte_with_arg(unsigned int a, INT32 b)
dd6bca2001-07-20Henrik Grubbström (Grubba) {
2315a62003-09-23Henrik Grubbström (Grubba)  ins_sparc_debug();
01de412002-11-08Henrik Grubbström (Grubba)  switch(a) { case F_NUMBER: sparc_push_int(b, 0); return; case F_NEG_NUMBER:
6a2a6d2005-06-23Henrik Grubbström (Grubba)  sparc_push_int(-(ptrdiff_t)b, 0);
01de412002-11-08Henrik Grubbström (Grubba)  return; case F_LFUN: sparc_push_lfun(b); return; case F_MARK_X:
6a2a6d2005-06-23Henrik Grubbström (Grubba)  sparc_mark(-(ptrdiff_t)b);
01de412002-11-08Henrik Grubbström (Grubba)  return;
ed16592002-11-09Henrik Grubbström (Grubba)  case F_LOCAL_LVALUE: sparc_local_lvalue(b); return;
9b35842005-06-27Henrik Grubbström (Grubba)  case F_POS_INT_INDEX: sparc_push_int(b, 0); low_ins_f_byte(F_INDEX, 1); return; case F_NEG_INT_INDEX: sparc_push_int(-(ptrdiff_t)b, 0); low_ins_f_byte(F_INDEX, 1); return;
01de412002-11-08Henrik Grubbström (Grubba)  }
7df3482001-07-21Henrik Grubbström (Grubba)  SET_REG(SPARC_REG_O0, b);
f1d1eb2001-07-20Henrik Grubbström (Grubba)  low_ins_f_byte(a, 1);
dd6bca2001-07-20Henrik Grubbström (Grubba)  return; } void ins_f_byte_with_2_args(unsigned int a,
112e5f2006-09-08Henrik Grubbström (Grubba)  INT32 c, INT32 b)
dd6bca2001-07-20Henrik Grubbström (Grubba) {
2315a62003-09-23Henrik Grubbström (Grubba)  ins_sparc_debug();
7df3482001-07-21Henrik Grubbström (Grubba)  SET_REG(SPARC_REG_O0, c); SET_REG(SPARC_REG_O1, b);
f1d1eb2001-07-20Henrik Grubbström (Grubba)  low_ins_f_byte(a, 1);
dd6bca2001-07-20Henrik Grubbström (Grubba)  return; }
697e0a2001-07-20Henrik Grubbström (Grubba)  #define addstr(s, l) low_my_binary_strcat((s), (l), buf) #define adddata2(s,l) addstr((char *)(s),(l) * sizeof((s)[0])); void sparc_encode_program(struct program *p, struct dynamic_buffer_s *buf) { size_t prev = 0, rel; /* De-relocate the program... */ for (rel = 0; rel < p->num_relocations; rel++) { size_t off = p->relocations[rel]; INT32 opcode; #ifdef PIKE_DEBUG if (off < prev) {
5aad932002-08-15Marcus Comstedt  Pike_fatal("Relocations in bad order!\n");
697e0a2001-07-20Henrik Grubbström (Grubba)  } #endif /* PIKE_DEBUG */ adddata2(p->program + prev, off - prev); #ifdef PIKE_DEBUG if ((p->program[off] & 0xc0000000) != 0x40000000) {
5aad932002-08-15Marcus Comstedt  Pike_fatal("Bad relocation!\n");
697e0a2001-07-20Henrik Grubbström (Grubba)  } #endif /* PIKE_DEBUG */ /* Relocate to being relative to NULL */ opcode = 0x40000000 |
6a2a6d2005-06-23Henrik Grubbström (Grubba)  ((p->program[off] + (((INT32)(ptrdiff_t)(p->program)>>2))) & 0x3fffffff);
697e0a2001-07-20Henrik Grubbström (Grubba)  adddata2(&opcode, 1); prev = off+1; } adddata2(p->program + prev, p->num_program - prev); } void sparc_decode_program(struct program *p) { /* Relocate the program... */ PIKE_OPCODE_T *prog = p->program;
6a2a6d2005-06-23Henrik Grubbström (Grubba)  INT32 delta = ((INT32)(ptrdiff_t)p->program)>>2;
697e0a2001-07-20Henrik Grubbström (Grubba)  size_t rel = p->num_relocations; while (rel--) { #ifdef PIKE_DEBUG if ((prog[p->relocations[rel]] & 0xc0000000) != 0x40000000) { Pike_error("Bad relocation: %d, off:%d, opcode: 0x%08x\n", rel, p->relocations[rel], prog[p->relocations[rel]]); } #endif /* PIKE_DEBUG */ prog[p->relocations[rel]] = 0x40000000 | (((prog[p->relocations[rel]] & 0x3fffffff) - delta) & 0x3fffffff); } }
9d2e2d2001-07-21Henrik Grubbström (Grubba)  /* * Inline machine-code... */ const unsigned INT32 sparc_flush_instruction_cache[] = { /* * On entry: * %o0 : void *ptr * %o1 : size_t nbytes * * cmp %o1, #1 * .l0: * flush %o0+%o1 * bge,a .l0 * subcc %o1, 8, %o1 * retl * or %g0,%g0,%o0 */ /* 1000 0000 1010 0000 0010 0000 0000 0000 */ 0x80a02000|(SPARC_REG_O1<<14)|1, /* 1000 0001 1101 1000 0000 0000 0000 0000 */ 0x81d80000|(SPARC_REG_O0<<14)|(SPARC_REG_O1), /* 0011 0110 1000 0000 0000 0000 0000 0000 */ 0x36800000|((-1)&0x3fffff), /* 1000 0000 1010 0000 0010 0000 0000 0000 */ 0x80a02000|(SPARC_REG_O1<<25)|(SPARC_REG_O1<<14)|8, /* 1000 0001 1100 0000 0010 0000 0000 0000 */ 0x81c02000|(SPARC_REG_O7<<14)|8, /* 1000 0000 0001 0000 0000 0000 0000 0000 */ 0x80100000|(SPARC_REG_O0<<25), };
f5e8622002-11-07Henrik Grubbström (Grubba) 
47451f2002-11-07Henrik Grubbström (Grubba) static void sparc_disass_rd_reg(int reg_no) { switch(reg_no & 0x1f) { case SPARC_RD_REG_CCR: fprintf(stderr, "%%ccr"); break; case SPARC_RD_REG_PC: fprintf(stderr, "%%pc"); break; default: fprintf(stderr, "%%sr(%d)", reg_no & 0x1f); break; } }
f5e8622002-11-07Henrik Grubbström (Grubba) static void sparc_disass_reg(int reg_no) { fprintf(stderr, "%%%c%1x", "goli"[(reg_no>>3)&3], reg_no & 7); } void sparc_disassemble_code(void *addr, size_t bytes) { unsigned INT32 *code = addr; size_t len = (bytes+3)>>2; while(len--) { unsigned INT32 opcode = *code; fprintf(stderr, "%p %08x ", code, opcode); switch(opcode & 0xc0000000) { case 0x00000000: { /* Sethi etc. */ int op2 = (opcode >> 22) & 0x7; switch(op2) { case 4: fprintf(stderr, "sethi %%hi(0x%08x), ", opcode << 10); break; } sparc_disass_reg(opcode>>25); fprintf(stderr, "\n"); } break; case 0x40000000: /* Call */ fprintf(stderr, "call 0x%p\n", ((char *)code) + (opcode << 2)); break; case 0x80000000: { /* ALU operation. */ int op3 = (opcode >> 19) & 0x3f; char buf[16]; char *mnemonic = NULL; if (!(op3 & 0x20)) { switch(op3 & 0xf) { case SPARC_OP3_ADD: mnemonic = "add"; break; /* 0 */ case SPARC_OP3_AND: mnemonic = "and"; break; /* 1 */ case SPARC_OP3_OR: mnemonic = "or"; break; /* 2 */ case SPARC_OP3_XOR: mnemonic = "xor"; break; /* 3 */ case SPARC_OP3_SUB: mnemonic = "sub"; break; /* 4 */ case SPARC_OP3_ANDN: mnemonic = "andn"; break; /* 5 */ case SPARC_OP3_ORN: mnemonic = "orn"; break; /* 6 */ case SPARC_OP3_XNOR: mnemonic = "xnor"; break; /* 7 */ case SPARC_OP3_ADDC: mnemonic = "addc"; break; /* 8 */ case SPARC_OP3_SUBC: mnemonic = "subc"; break; /* c */ default: sprintf(buf, "op3(0x%02x)", op3 & 0xf); mnemonic = buf; break; } if (op3 & 0x10) { fprintf(stderr, "%scc ", mnemonic); } else { fprintf(stderr, "%s ", mnemonic); } } else { switch(op3) { case SPARC_OP3_SLL: mnemonic = "sll"; break; case SPARC_OP3_SRL: mnemonic = "srl"; break; case SPARC_OP3_SRA: mnemonic = "sra"; break;
47451f2002-11-07Henrik Grubbström (Grubba)  case SPARC_OP3_RD: mnemonic = "rd"; break;
c0a5182002-11-10Henrik Grubbström (Grubba)  case SPARC_OP3_JMPL: mnemonic = "jmpl"; break; case SPARC_OP3_RETURN:mnemonic = "return"; break;
f5e8622002-11-07Henrik Grubbström (Grubba)  case SPARC_OP3_SAVE: mnemonic = "save"; break;
c0a5182002-11-10Henrik Grubbström (Grubba)  case SPARC_OP3_RESTORE:mnemonic = "restore"; break;
f5e8622002-11-07Henrik Grubbström (Grubba)  default: sprintf(buf, "op3(0x%02x)", op3); mnemonic = buf; break; } fprintf(stderr, "%s ", mnemonic); }
47451f2002-11-07Henrik Grubbström (Grubba)  if (op3 == SPARC_OP3_RD) { sparc_disass_rd_reg(opcode>>14); fprintf(stderr, ", ");
f5e8622002-11-07Henrik Grubbström (Grubba)  } else {
47451f2002-11-07Henrik Grubbström (Grubba)  sparc_disass_reg(opcode>>14);
f5e8622002-11-07Henrik Grubbström (Grubba)  fprintf(stderr, ", ");
47451f2002-11-07Henrik Grubbström (Grubba)  if (opcode & 0x00002000) { fprintf(stderr, "0x%04x, ", opcode & 0x1fff); } else { sparc_disass_reg(opcode); fprintf(stderr, ", "); }
f5e8622002-11-07Henrik Grubbström (Grubba)  } sparc_disass_reg(opcode >> 25); fprintf(stderr, "\n"); } break; case 0xc0000000: { /* Memory operations. */ int op3 = (opcode >> 19) & 0x3f; char buf[16]; char *mnemonic = NULL; switch(op3) { case 0x00: mnemonic="lduw"; break; case 0x01: mnemonic="ldub"; break; case 0x02: mnemonic="lduh"; break; case 0x03: mnemonic="ldd"; break; case 0x04: mnemonic="stw"; break; case 0x05: mnemonic="stb"; break; case 0x06: mnemonic="sth"; break; case 0x07: mnemonic="std"; break; case 0x08: mnemonic="ldsw"; break; case 0x09: mnemonic="ldsb"; break; case 0x0a: mnemonic="ldsh"; break; case 0x0b: mnemonic="ldx"; break; case 0x0e: mnemonic="stx"; break; default: sprintf(buf, "op3(0x%02x)", op3); mnemonic = buf; break; } if (op3 & 0x04) { /* Store */ fprintf(stderr, "%s ", mnemonic); sparc_disass_reg(opcode >> 25); fprintf(stderr, ", ["); sparc_disass_reg(opcode >> 14); if (opcode & 0x00002000) { fprintf(stderr, ", 0x%04x", opcode & 0x1fff); } else { fprintf(stderr, ", "); sparc_disass_reg(opcode); } fprintf(stderr, "]\n"); } else { /* Load */ fprintf(stderr, "%s [", mnemonic); sparc_disass_reg(opcode >> 14); if (opcode & 0x00002000) { fprintf(stderr, ", 0x%04x", opcode & 0x1fff); } else { fprintf(stderr, ", "); sparc_disass_reg(opcode); } fprintf(stderr, "], "); sparc_disass_reg(opcode >> 25); fprintf(stderr, "\n"); } } break; } code++; } }