|
|
|
|
|
|
|
|
|
|
|
|
#include "global.h" |
#include "svalue.h" |
#include "operators.h" |
#include "object.h" |
#include "builtin_functions.h" |
|
|
|
|
|
#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 */ |
|
|
|
|
|
#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 |
#define SPARC_OP3_ADD 0x00 |
#define SPARC_OP3_ADDcc 0x10 |
#define SPARC_OP3_ADDC 0x08 |
#define SPARC_OP3_ADDCcc 0x18 |
#define SPARC_OP3_SUB 0x04 |
#define SPARC_OP3_SUBcc 0x14 |
#define SPARC_OP3_SUBC 0x0c |
#define SPARC_OP3_SUBCcc 0x1c |
#define SPARC_OP3_SLL 0x25 |
#define SPARC_OP3_SRL 0x26 |
#define SPARC_OP3_SRA 0x27 |
#define SPARC_OP3_RD 0x28 |
#define SPARC_OP3_JMPL 0x38 |
#define SPARC_OP3_RETURN 0x39 |
#define SPARC_OP3_SAVE 0x3c |
#define SPARC_OP3_RESTORE 0x3d |
|
#define SPARC_RD_REG_CCR 0x02 |
#define SPARC_RD_REG_PC 0x05 |
|
#define SPARC_ALU_OP(OP3, D, S1, S2, I) \ |
add_to_program(0x80000000|((D)<<25)|((OP3)<<19)|((S1)<<14)|((I)<<13)| \ |
((S2)&0x1fff)) |
|
#define SPARC_OP3_LDUW 0x00 |
#define SPARC_OP3_LDUH 0x02 |
#define SPARC_OP3_LDUB 0x01 |
#define SPARC_OP3_LDSW 0x08 |
#define SPARC_OP3_LDSH 0x0a |
#define SPARC_OP3_LDSB 0x08 |
#define SPARC_OP3_LDX 0x0b |
#define SPARC_OP3_STW 0x04 |
#define SPARC_OP3_STH 0x06 |
#define SPARC_OP3_STX 0x0e |
|
#define SPARC_MEM_OP(OP3, D, S1, S2, I) \ |
add_to_program(0xc0000000|((D)<<25)|((OP3)<<19)|((S1)<<14)|((I)<<13)| \ |
((S2)&0x1fff)) |
|
#define SPARC_ANDcc(D,S1,S2,I) SPARC_ALU_OP(SPARC_OP3_ANDcc, D, S1, S2, I) |
#define SPARC_OR(D,S1,S2,I) SPARC_ALU_OP(SPARC_OP3_OR, D, S1, S2, I) |
#define SPARC_XOR(D,S1,S2,I) SPARC_ALU_OP(SPARC_OP3_XOR, D, S1, S2, I) |
|
#define SPARC_SRA(D,S1,S2,I) SPARC_ALU_OP(SPARC_OP3_SRA, D, S1, S2, I) |
#define SPARC_SLL(D,S1,S2,I) SPARC_ALU_OP(SPARC_OP3_SLL, D, S1, S2, I) |
|
#define SPARC_ADD(D,S1,S2,I) SPARC_ALU_OP(SPARC_OP3_ADD, D, S1, S2, I) |
#define SPARC_SUBcc(D,S1,S2,I) SPARC_ALU_OP(SPARC_OP3_SUBcc, D, S1, S2, I) |
|
#define SPARC_RD(D, RDREG) SPARC_ALU_OP(SPARC_OP3_RD, D, RDREG, 0, 0) |
|
#define SPARC_RETURN(S1, S2, I) SPARC_ALU_OP(SPARC_OP3_RETURN, 0, S1, S2, I) |
|
#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) |
|
#define SPARC_LDX(D,S1,S2,I) SPARC_MEM_OP(SPARC_OP3_LDX, D, S1, S2, I) |
#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) |
|
#define SPARC_STX(D,S1,S2,I) SPARC_MEM_OP(SPARC_OP3_STX, D, S1, S2, I) |
#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) |
|
#define SPARC_SETHI(D, VAL) \ |
add_to_program(0x01000000|((D)<<25)|(((VAL)>>10)&0x3fffff)) |
#define SPARC_NOOP() SPARC_SETHI(SPARC_REG_G0, 0) |
|
#define SPARC_BA(DISP22, A) \ |
add_to_program(0x10800000|((A)<<29)|(((DISP22)>>2)&0x1fffff)) |
|
#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)) |
|
#define SPARC_CALL(DISP30) \ |
add_to_program(0x40000000 | (((DISP30) >> 2) & 0x3fffffff)) |
|
|
#define SET_REG(REG, X) do { \ |
INT64 val_ = X; \ |
INT32 reg_ = REG; \ |
/*fprintf(stderr, "SET_REG(0x%02x, %p)\n", reg_, (void *)val_);*/ \ |
if ((-4096 <= val_) && (val_ <= 4095)) { \ |
/* or %g0, val_, reg */ \ |
SPARC_OR(reg_, SPARC_REG_G0, val_, 1); \ |
} 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_); \ |
} \ |
} else { \ |
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)) { \ |
/* 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); \ |
} \ |
} else { \ |
/* FIXME: SPARC64 */ \ |
Pike_fatal("Value out of range: %p\n", (void *)val_); \ |
} \ |
} \ |
} while(0) |
|
|
#define ADD_CALL(X, DELAY_OK) do { \ |
PIKE_OPCODE_T *ptr_ = (PIKE_OPCODE_T *)(X); \ |
ptrdiff_t delta_; \ |
struct program *p_ = Pike_compiler->new_program; \ |
INT32 off_ = p_->num_program; \ |
/* 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... */ \ |
} \ |
/*fprintf(stderr, "call %p (pc:%p)\n", ptr_, p_->program);*/ \ |
/* call X */ \ |
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); \ |
} \ |
add_to_program(delay_); \ |
sparc_last_pc = off_; /* Value in %o7. */ \ |
sparc_codegen_state |= SPARC_CODEGEN_PC_IS_SET; \ |
} while(0) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#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 |
#define SPARC_REG_PIKE_OBJ SPARC_REG_L4 |
#define SPARC_REG_PIKE_DEBUG SPARC_REG_L7 |
#define SPARC_REG_SP SPARC_REG_O6 |
#define SPARC_REG_PC SPARC_REG_O7 |
|
|
|
|
unsigned INT32 sparc_codegen_state = 0; |
static int sparc_pike_sp_bias = 0; |
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 */ |
|
#define LOAD_PIKE_INTERPRETER() do { \ |
if (!(sparc_codegen_state & SPARC_CODEGEN_IP_IS_SET)) { \ |
SET_REG(SPARC_REG_PIKE_IP, \ |
((ptrdiff_t)(&Pike_interpreter_pointer))); \ |
PIKE_LDPTR(SPARC_REG_PIKE_IP, SPARC_REG_PIKE_IP, 0, 1); \ |
sparc_codegen_state |= SPARC_CODEGEN_IP_IS_SET; \ |
} \ |
} while(0) |
|
#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 */ \ |
PIKE_LDPTR(SPARC_REG_PIKE_FP, SPARC_REG_PIKE_IP, \ |
OFFSETOF(Pike_interpreter_struct, 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 */ \ |
PIKE_LDPTR(SPARC_REG_PIKE_SP, SPARC_REG_PIKE_IP, \ |
OFFSETOF(Pike_interpreter_struct, stack_pointer), 1); \ |
sparc_codegen_state |= SPARC_CODEGEN_SP_IS_SET; \ |
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; \ |
} \ |
} 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 */ \ |
PIKE_LDPTR(SPARC_REG_PIKE_MARK_SP, SPARC_REG_PIKE_IP, \ |
OFFSETOF(Pike_interpreter_struct, mark_stack_pointer), 1); \ |
sparc_codegen_state |= SPARC_CODEGEN_MARK_SP_IS_SET; \ |
} \ |
} while(0) |
|
#define SPARC_FLUSH_UNSTORED() do { \ |
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; \ |
} \ |
if (sparc_codegen_state & SPARC_CODEGEN_MARK_SP_NEEDS_STORE) { \ |
/* stw %pike_mark_sp, [ %ip, %offset(Pike_interpreter, mark_stack_pointer) ] */ \ |
PIKE_STPTR(SPARC_REG_PIKE_MARK_SP, SPARC_REG_PIKE_IP, \ |
OFFSETOF(Pike_interpreter_struct, mark_stack_pointer), 1); \ |
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) ] */ \ |
PIKE_STPTR(SPARC_REG_PIKE_SP, SPARC_REG_PIKE_IP, \ |
OFFSETOF(Pike_interpreter_struct, stack_pointer), 1); \ |
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)) |
|
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) |
|
#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 */ |
|
|
|
|
|
|
void sparc_ins_entry(void) |
{ |
#ifdef PIKE_BYTECODE_SPARC64 |
|
add_to_program(0x81e02000|(SPARC_REG_SP<<25)| |
(SPARC_REG_SP<<14)|((-176)&0x1fff)); |
#else /* !PIKE_BYTECODE_SPARC64 */ |
|
add_to_program(0x81e02000|(SPARC_REG_SP<<25)| |
(SPARC_REG_SP<<14)|((-112)&0x1fff)); |
#endif /* PIKE_BYTECODE_SPARC64 */ |
#if 0 |
SPARC_OR(SPARC_REG_O0, SPARC_REG_G0, SPARC_REG_O7, 0); |
ADD_CALL(sparc_trace_fun, 1); |
#endif /* 0 */ |
FLUSH_CODE_GENERATOR_STATE(); |
} |
|
|
void sparc_update_pc(void) |
{ |
LOAD_PIKE_FP(); |
#ifdef PIKE_BYTECODE_SPARC64 |
|
|
SPARC_RD(SPARC_REG_O7, SPARC_RD_REG_PC); |
#else /* !0 */ |
|
SPARC_CALL(8); |
|
#endif /* 0 */ |
|
PIKE_STPTR(SPARC_REG_O7, SPARC_REG_PIKE_FP, OFFSETOF(pike_frame, pc), 1); |
} |
|
|
|
|
|
#define MAKE_TYPE_WORD(TYPE, SUB_TYPE) (((TYPE) << 16)|(SUB_TYPE)) |
|
static void sparc_incr_mark_sp(int delta) |
{ |
LOAD_PIKE_MARK_SP(); |
|
SPARC_ADD(SPARC_REG_PIKE_MARK_SP, SPARC_REG_PIKE_MARK_SP, |
sizeof(void *)*delta, 1); |
sparc_codegen_state |= SPARC_CODEGEN_MARK_SP_NEEDS_STORE; |
} |
|
static void sparc_mark(ptrdiff_t off) |
{ |
LOAD_PIKE_SP(); |
LOAD_PIKE_MARK_SP(); |
off *= sizeof(struct svalue); |
off += sparc_pike_sp_bias; |
if (off) { |
if ((-4096 <= off) && (off < 4096)) { |
|
SPARC_ADD(SPARC_REG_I0, SPARC_REG_PIKE_SP, off, 1); |
} else { |
SET_REG(SPARC_REG_I0, off); |
|
SPARC_ADD(SPARC_REG_I0, SPARC_REG_PIKE_SP, SPARC_REG_I0, 0); |
} |
|
PIKE_STPTR(SPARC_REG_I0, SPARC_REG_PIKE_MARK_SP, SPARC_REG_G0, 0); |
} else { |
|
PIKE_STPTR(SPARC_REG_PIKE_SP, SPARC_REG_PIKE_MARK_SP, SPARC_REG_G0, 0); |
} |
sparc_incr_mark_sp(1); |
} |
|
static void sparc_push_int(INT_TYPE x, int sub_type) |
{ |
INT32 type_word = MAKE_TYPE_WORD(PIKE_T_INT, sub_type); |
int reg = SPARC_REG_G0; |
|
LOAD_PIKE_SP(); |
|
#ifdef PIKE_DEBUG |
if (sizeof(struct svalue) > 8) { |
size_t e; |
for (e = 4; e < sizeof(struct svalue); e += 4) { |
|
if (e == OFFSETOF(svalue, u.integer)) continue; |
|
SPARC_STW(SPARC_REG_G0, SPARC_REG_PIKE_SP, sparc_pike_sp_bias + e, 1); |
} |
} |
#endif /* PIKE_DEBUG */ |
if (x) { |
SET_REG(SPARC_REG_I1, x); |
reg = SPARC_REG_I1; |
} |
if (sizeof(INT_TYPE) == 4) { |
SPARC_STW(reg, SPARC_REG_PIKE_SP, |
sparc_pike_sp_bias + OFFSETOF(svalue, u.integer), 1); |
} else { |
SPARC_STX(reg, SPARC_REG_PIKE_SP, |
sparc_pike_sp_bias + OFFSETOF(svalue, u.integer), 1); |
} |
if (!type_word) { |
reg = SPARC_REG_G0; |
} else if (x != type_word) { |
SET_REG(SPARC_REG_I1, type_word); |
reg = SPARC_REG_I1; |
} |
|
SPARC_STW(reg, SPARC_REG_PIKE_SP, sparc_pike_sp_bias, 1); |
sparc_pike_sp_bias += sizeof(struct svalue); |
sparc_codegen_state |= SPARC_CODEGEN_SP_NEEDS_STORE; |
} |
|
static void sparc_clear_string_subtype(void) |
{ |
LOAD_PIKE_SP(); |
|
SPARC_LDUH(SPARC_REG_I0, SPARC_REG_PIKE_SP, |
sparc_pike_sp_bias + OFFSETOF(svalue, tu.t.type), 1); |
|
SPARC_SUBcc(SPARC_REG_G0, SPARC_REG_I0, PIKE_T_INT, 1); |
|
SPARC_BE(8, 1); |
|
SPARC_STH(SPARC_REG_G0, SPARC_REG_PIKE_SP, |
sparc_pike_sp_bias + OFFSETOF(svalue, tu.t.subtype), 1); |
} |
|
static void sparc_push_lfun(unsigned int no) |
{ |
LOAD_PIKE_FP(); |
LOAD_PIKE_SP(); |
|
PIKE_LDPTR(SPARC_REG_PIKE_OBJ, SPARC_REG_PIKE_FP, |
OFFSETOF(pike_frame, current_object), 1); |
|
PIKE_STPTR(SPARC_REG_PIKE_OBJ, SPARC_REG_PIKE_SP, |
sparc_pike_sp_bias + OFFSETOF(svalue, u.object), 1); |
|
SPARC_LDUW(SPARC_REG_I0, SPARC_REG_PIKE_OBJ, |
OFFSETOF(object, refs), 1); |
|
SPARC_ADD(SPARC_REG_I0, SPARC_REG_I0, 1, 1); |
|
PIKE_LDPTR(SPARC_REG_I1, SPARC_REG_PIKE_FP, |
OFFSETOF(pike_frame, context), 1); |
|
SPARC_STW(SPARC_REG_I0, SPARC_REG_PIKE_OBJ, |
OFFSETOF(object, refs), 1); |
|
SPARC_LDUH(SPARC_REG_I1, SPARC_REG_I1, |
OFFSETOF(inherit, identifier_level), 1); |
SET_REG(SPARC_REG_I2, (no & 0xffff) | (PIKE_T_FUNCTION << 16)); |
|
SPARC_ADD(SPARC_REG_I1, SPARC_REG_I1, SPARC_REG_I2, 0); |
|
SPARC_STW(SPARC_REG_I1, SPARC_REG_PIKE_SP, sparc_pike_sp_bias, 1); |
sparc_pike_sp_bias += sizeof(struct svalue); |
sparc_codegen_state |= SPARC_CODEGEN_SP_NEEDS_STORE; |
} |
|
void sparc_local_lvalue(unsigned int no) |
{ |
LOAD_PIKE_SP(); |
LOAD_PIKE_FP(); |
SET_REG(SPARC_REG_I0, T_SVALUE_PTR); |
|
SPARC_STH(SPARC_REG_I0, SPARC_REG_PIKE_SP, sparc_pike_sp_bias, 1); |
SET_REG(SPARC_REG_I0, T_VOID); |
no *= sizeof(struct svalue); |
if (no < 4096) { |
|
PIKE_LDPTR(SPARC_REG_I2, SPARC_REG_PIKE_FP, |
OFFSETOF(pike_frame, locals), 1); |
|
SPARC_ADD(SPARC_REG_I2, SPARC_REG_I2, no, 1); |
} else { |
SET_REG(SPARC_REG_I1, no); |
|
PIKE_LDPTR(SPARC_REG_I2, SPARC_REG_PIKE_FP, |
OFFSETOF(pike_frame, locals), 1); |
|
SPARC_ADD(SPARC_REG_I2, SPARC_REG_I2, SPARC_REG_I1, 0); |
} |
|
PIKE_STPTR(SPARC_REG_I2, SPARC_REG_PIKE_SP, |
sparc_pike_sp_bias + OFFSETOF(svalue, u.lval), 1); |
sparc_pike_sp_bias += sizeof(struct svalue) * 2; |
|
SPARC_STH(SPARC_REG_I0, SPARC_REG_PIKE_SP, |
sparc_pike_sp_bias - sizeof(struct svalue), 1); |
sparc_codegen_state |= SPARC_CODEGEN_SP_NEEDS_STORE; |
} |
|
|
|
|
|
#ifdef PIKE_DEBUG |
void sparc_debug_check_registers(int state, |
struct Pike_interpreter_struct *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_pointer)) || |
((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_pointer, |
(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)) { |
SET_REG(SPARC_REG_PIKE_DEBUG, ((ptrdiff_t)(&d_flag))); |
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); |
#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); |
SPARC_ADD(SPARC_REG_O3, SPARC_REG_PIKE_SP, sparc_pike_sp_bias, 1); |
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 */ |
|
SPARC_BE(6*4, 0); |
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); |
SPARC_ADD(SPARC_REG_O3, SPARC_REG_PIKE_SP, sparc_pike_sp_bias, 1); |
SPARC_OR(SPARC_REG_O4, SPARC_REG_PIKE_MARK_SP, SPARC_REG_G0, 0); |
ADD_CALL(sparc_debug_check_registers, 1); |
#endif /* PIKE_BYTECODE_SPARC64 */ |
} |
} |
#else /* !PIKE_DEBUG */ |
#define ins_sparc_debug() |
#endif /* PIKE_DEBUG */ |
|
static void low_ins_call(void *addr, int delay_ok, int i_flags) |
{ |
LOAD_PIKE_INTERPRETER(); |
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(); |
|
|
|
|
|
|
|
PIKE_STPTR(SPARC_REG_O7, SPARC_REG_PIKE_FP, OFFSETOF(pike_frame, pc), 1); |
|
delay_ok = 1; |
} |
} |
|
ADD_CALL(addr, delay_ok); |
|
#if 1 |
|
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 */ |
|
SPARC_UNLOAD_CACHED(); |
#endif /* 1 */ |
} |
|
static void low_ins_f_byte(unsigned int b, int delay_ok) |
{ |
void *addr; |
|
b-=F_OFFSET; |
#ifdef PIKE_DEBUG |
if(b>255) |
Pike_error("Instruction too big %d\n",b); |
#endif |
|
addr = instrs[b].address; |
|
#ifdef PIKE_DEBUG |
if (d_flag < 3) |
#endif |
|
switch(b) |
{ |
case F_MARK2 - F_OFFSET: |
sparc_mark(0); |
|
case F_SYNCH_MARK - F_OFFSET: |
case F_MARK - F_OFFSET: |
sparc_mark(0); |
return; |
|
case F_POP_MARK - F_OFFSET: |
sparc_incr_mark_sp(-1); |
return; |
case F_UNDEFINED - F_OFFSET: |
sparc_push_int(0, 1); |
return; |
|
case F_MARK_AND_CONST0 - F_OFFSET: |
sparc_mark(0); |
|
case F_CONST0 - F_OFFSET: |
sparc_push_int(0, 0); |
return; |
|
case F_MARK_AND_CONST1 - F_OFFSET: |
sparc_mark(0); |
|
case F_CONST1 - F_OFFSET: |
sparc_push_int(1, 0); |
return; |
|
case F_CONST_1 - F_OFFSET: |
sparc_push_int(-1, 0); |
return; |
case F_BIGNUM - F_OFFSET: |
sparc_push_int(0x7fffffff, 0); |
return; |
|
case F_EXIT_CATCH - F_OFFSET: |
sparc_push_int(0, 1); |
addr = instrs[b = F_ESCAPE_CATCH-F_OFFSET].address; |
break; |
|
case F_MAKE_ITERATOR - F_OFFSET: |
{ |
SET_REG(SPARC_REG_O0, 1); |
delay_ok = 1; |
addr = (void *)f_get_iterator; |
} |
break; |
|
case F_ADD - F_OFFSET: |
SET_REG(SPARC_REG_O0, 2); |
delay_ok = 1; |
addr = (void *)f_add; |
break; |
|
} |
|
low_ins_call(addr, delay_ok, instrs[b].flags); |
} |
|
void ins_f_byte(unsigned int opcode) |
{ |
ins_sparc_debug(); |
low_ins_f_byte(opcode, 0); |
} |
|
void ins_f_byte_with_arg(unsigned int a, INT32 b) |
{ |
ins_sparc_debug(); |
|
switch(a) { |
case F_NUMBER: |
sparc_push_int(b, 0); |
return; |
case F_NEG_NUMBER: |
sparc_push_int(-(ptrdiff_t)b, 0); |
return; |
case F_LFUN: |
sparc_push_lfun(b); |
return; |
case F_MARK_X: |
sparc_mark(-(ptrdiff_t)b); |
return; |
case F_LOCAL_LVALUE: |
sparc_local_lvalue(b); |
return; |
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; |
} |
SET_REG(SPARC_REG_O0, b); |
low_ins_f_byte(a, 1); |
return; |
} |
|
void ins_f_byte_with_2_args(unsigned int a, |
INT32 c, |
INT32 b) |
{ |
ins_sparc_debug(); |
|
SET_REG(SPARC_REG_O0, c); |
SET_REG(SPARC_REG_O1, b); |
low_ins_f_byte(a, 1); |
return; |
} |
|
#define addstr(s, l) low_my_binary_strcat((s), (l), buf) |
#define adddata2(s,l) addstr((char *)(s),(l) * sizeof((s)[0])); |
|
int sparc_force_fp(void) |
{ |
return 0; |
} |
|
void sparc_encode_program(struct program *p, struct dynamic_buffer_s *buf) |
{ |
size_t prev = 0, rel; |
|
for (rel = 0; rel < p->num_relocations; rel++) { |
size_t off = p->relocations[rel]; |
INT32 opcode; |
#ifdef PIKE_DEBUG |
if (off < prev) { |
Pike_fatal("Relocations in bad order!\n"); |
} |
#endif /* PIKE_DEBUG */ |
adddata2(p->program + prev, off - prev); |
|
#ifdef PIKE_DEBUG |
if ((p->program[off] & 0xc0000000) != 0x40000000) { |
Pike_fatal("Bad relocation!\n"); |
} |
#endif /* PIKE_DEBUG */ |
|
opcode = 0x40000000 | |
((p->program[off] + (((INT32)(ptrdiff_t)(p->program)>>2))) & 0x3fffffff); |
adddata2(&opcode, 1); |
prev = off+1; |
} |
adddata2(p->program + prev, p->num_program - prev); |
} |
|
void sparc_decode_program(struct program *p) |
{ |
|
PIKE_OPCODE_T *prog = p->program; |
INT32 delta = ((INT32)(ptrdiff_t)p->program)>>2; |
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); |
} |
} |
|
|
|
|
const unsigned INT32 sparc_flush_instruction_cache[] = { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
0x80a02000|(SPARC_REG_O1<<14)|1, |
|
0x81d80000|(SPARC_REG_O0<<14)|(SPARC_REG_O1), |
|
0x36800000|((-1)&0x3fffff), |
|
0x80a02000|(SPARC_REG_O1<<25)|(SPARC_REG_O1<<14)|8, |
|
0x81c02000|(SPARC_REG_O7<<14)|8, |
|
0x80100000|(SPARC_REG_O0<<25), |
}; |
|
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; |
} |
} |
|
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: |
{ |
|
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: |
|
fprintf(stderr, "call 0x%p\n", ((char *)code) + (opcode << 2)); |
break; |
case 0x80000000: |
{ |
|
int op3 = (opcode >> 19) & 0x3f; |
char buf[16]; |
char *mnemonic = NULL; |
if (!(op3 & 0x20)) { |
switch(op3 & 0xf) { |
case SPARC_OP3_ADD: mnemonic = "add"; break; |
case SPARC_OP3_AND: mnemonic = "and"; break; |
case SPARC_OP3_OR: mnemonic = "or"; break; |
case SPARC_OP3_XOR: mnemonic = "xor"; break; |
case SPARC_OP3_SUB: mnemonic = "sub"; break; |
case SPARC_OP3_ANDN: mnemonic = "andn"; break; |
case SPARC_OP3_ORN: mnemonic = "orn"; break; |
case SPARC_OP3_XNOR: mnemonic = "xnor"; break; |
case SPARC_OP3_ADDC: mnemonic = "addc"; break; |
|
case SPARC_OP3_SUBC: mnemonic = "subc"; break; |
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; |
case SPARC_OP3_RD: mnemonic = "rd"; break; |
case SPARC_OP3_JMPL: mnemonic = "jmpl"; break; |
case SPARC_OP3_RETURN:mnemonic = "return"; break; |
case SPARC_OP3_SAVE: mnemonic = "save"; break; |
case SPARC_OP3_RESTORE:mnemonic = "restore"; break; |
default: |
sprintf(buf, "op3(0x%02x)", op3); |
mnemonic = buf; |
break; |
} |
fprintf(stderr, "%s ", mnemonic); |
} |
if (op3 == SPARC_OP3_RD) { |
sparc_disass_rd_reg(opcode>>14); |
fprintf(stderr, ", "); |
} else { |
sparc_disass_reg(opcode>>14); |
fprintf(stderr, ", "); |
if (opcode & 0x00002000) { |
fprintf(stderr, "0x%04x, ", opcode & 0x1fff); |
} else { |
sparc_disass_reg(opcode); |
fprintf(stderr, ", "); |
} |
} |
sparc_disass_reg(opcode >> 25); |
fprintf(stderr, "\n"); |
} |
break; |
case 0xc0000000: |
{ |
|
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) { |
|
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 { |
|
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++; |
} |
} |
|
|