From: Julian Seward Date: Wed, 30 Jun 2004 09:28:04 +0000 (+0000) Subject: First draft of tree-based instruction selector. X-Git-Tag: svn/VALGRIND_3_0_1^2~1308 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a8fcb7fa02d5fc6d3f79c5b34ac3de9df315f2eb;p=thirdparty%2Fvalgrind.git First draft of tree-based instruction selector. git-svn-id: svn://svn.valgrind.org/vex/trunk@26 --- diff --git a/VEX/Makefile b/VEX/Makefile index 0c3f6f08bf..0e6cbea328 100644 --- a/VEX/Makefile +++ b/VEX/Makefile @@ -1,8 +1,11 @@ -INCLUDES = include/basictypes.h +INCLUDES = include/arena.h \ + include/basictypes.h include/ir_defs.h \ + include/host_regs.h include/x86h_defs.h ##OBJS = basictypes.o ir_defs.o arena.o linker.o dispatch.o -OBJS = basictypes.o ir_defs.o +OBJS = basictypes.o ir_defs.o host_regs.o \ + x86h_defs.o isel_x86.o test_main.o CC_OPTS = -g -Wall -Iinclude @@ -16,6 +19,12 @@ basictypes.o: basictypes.c $(INCLUDES) gcc $(CC_OPTS) -c basictypes.c ir_defs.o: ir_defs.c $(INCLUDES) gcc $(CC_OPTS) -c ir_defs.c +host_regs.o: host_regs.c $(INCLUDES) + gcc $(CC_OPTS) -c host_regs.c +x86h_defs.o: x86h_defs.c $(INCLUDES) + gcc $(CC_OPTS) -c x86h_defs.c +isel_x86.o: isel_x86.c $(INCLUDES) + gcc $(CC_OPTS) -c isel_x86.c arena.o: arena.c $(INCLUDES) gcc $(CC_OPTS) -c arena.c linker.o: linker.c $(INCLUDES) @@ -23,4 +32,7 @@ linker.o: linker.c $(INCLUDES) dispatch.o: dispatch.c $(INCLUDES) gcc $(CC_OPTS) -c dispatch.c +test_main.o: test_main.c $(INCLUDES) + gcc $(CC_OPTS) -c test_main.c + diff --git a/VEX/host_regs.c b/VEX/host_regs.c new file mode 100644 index 0000000000..2810896eb5 --- /dev/null +++ b/VEX/host_regs.c @@ -0,0 +1,51 @@ + +/*---------------------------------------------------------------*/ +/*--- ---*/ +/*--- This file (host_regs.c) is ---*/ +/*--- Copyright (c) 2004 OpenWorks LLP. All rights reserved. ---*/ +/*--- ---*/ +/*---------------------------------------------------------------*/ + +#include + +#include "basictypes.h" +#include "host_regs.h" + + +HReg mkHReg ( UInt regno, HRegClass rc, Bool virtual ) +{ + assert((regno & 0xFF000000) == 0); + return (regno << 8) | (((UInt)rc) << 4) | (virtual ? 1 : 0); +} + +HRegClass hregClass ( HReg r ) +{ + UInt rc = (r & 0x000000F0) >> 4; + assert(rc <= 2); + return (HRegClass)rc; +} + +Bool hregIsVirtual ( HReg r ) +{ + return (r & 1) ? True : False; +} + +UInt hregNumber ( HReg r ) +{ + return (((UInt)r) >> 8); +} + + +/* Generic printing for registers. */ +void ppHReg ( FILE* f, HReg r ) +{ + Char* maybe_v = hregIsVirtual(r) ? "v" : ""; + Int regNo = hregNumber(r); + switch (hregClass(r)) { + case HRcInt: fprintf(f, "%%%sr%d", maybe_v, regNo); return; + case HRcFloat: fprintf(f, "%%%sf%d", maybe_v, regNo); return; + case HRcVector: fprintf(f, "%%%sv%d", maybe_v, regNo); return; + default: panic("ppHReg"); + } +} + diff --git a/VEX/include/host_regs.h b/VEX/include/host_regs.h new file mode 100644 index 0000000000..a50b531470 --- /dev/null +++ b/VEX/include/host_regs.h @@ -0,0 +1,50 @@ + +/*---------------------------------------------------------------*/ +/*--- ---*/ +/*--- This file (host_regs.h) is ---*/ +/*--- Copyright (c) 2004 OpenWorks LLP. All rights reserved. ---*/ +/*--- ---*/ +/*---------------------------------------------------------------*/ + +#ifndef __HOST_REGS_H +#define __HOST_REGS_H + + +/* Host registers. Stuff to represent: + + - The register number + - The register class + - Whether or not the register is a virtual reg. + + Registers are a 32-bit Int, thusly: + + bits 31-8 register number + bits 7-4 are 0000b for real register, 0001b for virtual register + bits 3-0 are the register class. + + There are currently 3 register classes: + + int + floating + vector. +*/ + +typedef UInt HReg; + +typedef + enum { HRcInt=0, HRcFloat=1, HRcVector=2 } + HRegClass; + + +/* Print an HReg in a generic (non-target-specific) way. */ +extern void ppHReg ( FILE*, HReg ); + +/* Construct/destruct. */ +extern HReg mkHReg ( UInt regno, HRegClass rc, Bool virtual ); + +extern HRegClass hregClass ( HReg ); +extern Bool hregIsVirtual ( HReg ); +extern UInt hregNumber ( HReg ); + + +#endif /* ndef __HOST_REGS_H */ diff --git a/VEX/include/ir_defs.h b/VEX/include/ir_defs.h index 7063a185b8..e666146e20 100644 --- a/VEX/include/ir_defs.h +++ b/VEX/include/ir_defs.h @@ -9,45 +9,54 @@ #ifndef __IR_DEFS_H #define __IR_DEFS_H -#include /* FILE* */ - /*---------------------------------------------------------------*/ /*--- Type definitions for the IR ---*/ /*---------------------------------------------------------------*/ -/* Types */ +/* ------------------ Types ------------------ */ typedef enum { Ity_Bit, Ity_I8, Ity_I16, Ity_I32, Ity_I64 } IRType; +extern void ppIRType ( FILE* f, IRType ); + -/* Constants */ +/* ------------------ Constants ------------------ */ typedef - enum { Ico_u8, Ico_u16, Ico_u32, Ico_u64 } + enum { Ico_U8, Ico_U16, Ico_U32, Ico_U64 } IRConstTag; typedef struct _IRConst { IRConstTag tag; union { - UChar u8; - UShort u16; - UInt u32; - ULong u64; + UChar U8; + UShort U16; + UInt U32; + ULong U64; } Ico; } IRConst; +extern IRConst* IRConst_U8 ( UChar ); +extern IRConst* IRConst_U16 ( UShort ); +extern IRConst* IRConst_U32 ( UInt ); +extern IRConst* IRConst_U64 ( ULong ); + +extern void ppIRConst ( FILE* f, IRConst* ); -/* Temporaries */ + +/* ------------------ Temporaries ------------------ */ typedef int IRTemp; +extern void ppIRTemp ( FILE* f, IRTemp ); + -/* Binary and unary ops */ +/* ------------------ Binary and unary ops ------------------ */ typedef enum { Iop_Add32, @@ -65,9 +74,11 @@ typedef } IROp; +extern void ppIROp ( FILE* f, IROp ); -/* Expressions +/* ------------------ Expressions ------------------ */ +/* data Expr = GET Int Int -- offset, size | TMP Temp -- value of temporary @@ -111,9 +122,18 @@ typedef } IRExpr; +extern IRExpr* IRExpr_Get ( Int off, Int sz ); +extern IRExpr* IRExpr_Tmp ( IRTemp tmp ); +extern IRExpr* IRExpr_Binop ( IROp op, IRExpr* arg1, IRExpr* arg2 ); +extern IRExpr* IRExpr_Unop ( IROp op, IRExpr* arg ); +extern IRExpr* IRExpr_LDle ( IRType ty, IRExpr* addr ); +extern IRExpr* IRExpr_Const ( IRConst* con ); + +extern void ppIRExpr ( FILE* f, IRExpr* ); -/* Statements: +/* ------------------ Statements ------------------ */ +/* data Stmt = PUT Int Int Expr -- offset, size, value | TMP Temp Expr -- store value in Temp @@ -130,23 +150,30 @@ typedef struct { Int offset; Int size; - struct _IRExpr* expr; + IRExpr* expr; } Put; struct { IRTemp tmp; - struct _IRExpr* expr; + IRExpr* expr; } Tmp; struct { - struct _IRExpr* addr; - struct _IRExpr* data; + IRExpr* addr; + IRExpr* data; } STle; } Ist; struct _IRStmt* link; } IRStmt; +extern IRStmt* IRStmt_Put ( Int off, Int sz, IRExpr* value ); +extern IRStmt* IRStmt_Tmp ( IRTemp tmp, IRExpr* expr ); +extern IRStmt* IRStmt_STle ( IRExpr* addr, IRExpr* value ); + +extern void ppIRStmt ( FILE* f, IRStmt* ); + -/* Basic block enders. +/* ------------------ Basic block enders. ------------------ */ +/* IRConst represents a guest address, which is either a 32 or 64 bit integer, depending on the architecture we're simulating. @@ -178,52 +205,64 @@ typedef } IRNext; +extern IRNext* IRNext_UJump ( IRConst* dst ); + +extern void ppIRNext ( FILE* f, IRNext* ); + + +/* ------------------ Basic Blocks ------------------ */ + +/* A bunch of statements, expressions, etc, are incomplete without an + environment indicating the type of each IRTemp. So this provides + one. +*/ +typedef + struct { + IRTemp name; + IRType type; + } + IRTypeEnvMaplet; + +typedef + struct { + IRTypeEnvMaplet* map; + Int map_size; + Int map_used; + } + IRTypeEnv; + +extern void ppIRTypeEnv ( FILE* f, IRTypeEnv* ); + /* Basic blocks contain 3 fields: - - An association list, giving a type for each temp + - A table giving a type for each temp - A list of statements - A Next */ typedef struct _IRBB { - struct _IRStmt* stmts; - struct _IRNext* next; + IRTypeEnv* tyenv; + IRStmt* stmts; + IRNext* next; } IRBB; +extern IRBB* mk_IRBB ( IRTypeEnv*, IRStmt*, IRNext* ); + +extern void ppIRBB ( FILE* f, IRBB* ); + /*---------------------------------------------------------------*/ -/*--- Basic functions for the IR ---*/ +/*--- Helper functions for the IR ---*/ /*---------------------------------------------------------------*/ -/* Printers ... */ -extern void ppIRType ( FILE* f, IRType ); -extern void ppIRConst ( FILE* f, IRConst* ); -extern void ppIRTemp ( FILE* f, IRTemp ); -extern void ppIROp ( FILE* f, IROp ); -extern void ppIRExpr ( FILE* f, IRExpr* ); -extern void ppIRStmt ( FILE* f, IRStmt* ); -extern void ppIRNext ( FILE* f, IRNext* ); -extern void ppIRBB ( FILE* f, IRBB* ); - -/* Constructors -- IRExpr */ -extern IRExpr* mkExGet ( Int off, Int sz ); -extern IRExpr* mkExTmp ( IRTemp tmp ); -extern IRExpr* mkExBinop ( IROp op, IRExpr* arg1, IRExpr* arg2 ); -extern IRExpr* mkExUnop ( IROp op, IRExpr* arg ); -extern IRExpr* mkExLDle ( IRType ty, IRExpr* addr ); -extern IRExpr* mkExConst ( IRConst* con ); - -/* Constructors -- IRStmt */ -extern IRStmt* mkStPut ( Int off, Int sz, IRExpr* value ); -extern IRStmt* mkStTmp ( IRTemp tmp, IRExpr* expr ); -extern IRStmt* mkStSTle ( IRExpr* addr, IRExpr* value ); - -/* Constructors -- IRNext */ -extern IRNext* mkNxUJump ( IRConst* dst ); - -/* Constructors -- IRBB */ -extern IRBB* mkIRBB ( IRStmt* stmts, IRNext* next ); +/* For messing with IR type environments */ +extern IRTypeEnv* newIRTypeEnv ( void ); +extern void addToIRTypeEnv ( IRTypeEnv*, IRTemp, IRType ); +extern IRType lookupIRTypeEnv ( IRTypeEnv*, IRTemp ); + +/* What is the type of this expression? */ +extern IRType typeOfIRExpr ( IRTypeEnv*, IRExpr* ); #endif /* ndef __IR_DEFS_H */ diff --git a/VEX/include/x86h_defs.h b/VEX/include/x86h_defs.h new file mode 100644 index 0000000000..30c1185719 --- /dev/null +++ b/VEX/include/x86h_defs.h @@ -0,0 +1,150 @@ + +/*---------------------------------------------------------------*/ +/*--- ---*/ +/*--- This file (x86h_defs.h) is ---*/ +/*--- Copyright (c) 2004 OpenWorks LLP. All rights reserved. ---*/ +/*--- ---*/ +/*---------------------------------------------------------------*/ + +#ifndef __X86H_DEFS_H +#define __X86H_DEFS_H + + +/* --------- Registers. --------- */ + +/* The usual HReg abstraction. There are 8 real int regs, + 6 real float regs, and 0 real vector regs. +*/ + +extern void ppHRegX86 ( FILE*, HReg ); + + +/* --------- Memory address expressions (amodes). --------- */ + +typedef + enum { + Xam_IR, + Xam_IRRS + } + X86AModeTag; + +typedef + struct { + X86AModeTag tag; + union { + struct { + UInt imm; + HReg reg; + } IR; + struct { + UInt imm; + HReg base; + HReg index; + Int shift; /* 0, 1, 2 or 3 only */ + } IRRS; + } Xam; + } + X86AMode; + +extern X86AMode* X86AMode_IR ( UInt, HReg ); +extern X86AMode* X86AMode_IRRS ( UInt, HReg, HReg, Int ); + +extern void ppX86AMode ( FILE*, X86AMode* ); + + +/* --------- Operands. Not all are valid for all insns. --------- */ + +typedef + enum { + Xop_Imm, + Xop_Reg, + Xop_Mem + } + X86OperandTag; + +typedef + struct { + X86OperandTag tag; + union { + struct { + UInt imm32; + } Imm; + struct { + HReg reg; + } Reg; + struct { + X86AMode* am; + } Mem; + } + Xop; + } + X86Operand; + +extern X86Operand* X86Operand_Imm ( UInt ); +extern X86Operand* X86Operand_Reg ( HReg ); +extern X86Operand* X86Operand_Mem ( X86AMode* ); + +extern void ppX86Operand ( FILE*, X86Operand* ); + + +/* --------- Instructions. --------- */ + +typedef + enum { Xalu_ADD, Xalu_SUB, Xalu_ADC, Xalu_SBB, Xalu_AND, Xalu_OR, Xalu_XOR } + X86AluOp; + +extern void ppX86AluOp ( FILE*, X86AluOp ); + + +typedef + enum { + Xin_LD32, /* 32-bit integer load */ + Xin_ST32, /* 32-bit integer store */ + Xin_Alu32, /* 32-bit arith/logical, R-R, R-M, M-R */ + Xin_Mov32, /* 32-bit move R-R R-M M-R I-R I-M */ + Xin_Alu16 /* 16-bit arith/logical, R-R, R-M, M-R */ + } + X86InstrTag; + +/* Destinations are on the RIGHT (second operand). */ + +typedef + struct { + X86InstrTag tag; + union { + struct { + HReg src; + X86AMode* dst; + } ST32; + struct { + X86AMode* src; + HReg dst; + } LD32; + struct { + X86AluOp op; + X86Operand* src; + X86Operand* dst; + } Alu32; + struct { + X86Operand* src; + X86Operand* dst; + } Mov32; + struct { + X86AluOp op; + X86Operand* src; + X86Operand* dst; + } Alu16; + } Xin; + } + X86Instr; + +extern X86Instr* X86Instr_ST32 ( HReg, X86AMode* ); +extern X86Instr* X86Instr_LD32 ( X86AMode*, HReg ); +extern X86Instr* X86Instr_Alu32 ( X86AluOp, X86Operand*, X86Operand* ); +extern X86Instr* X86Instr_Mov32 ( X86Operand*, X86Operand* ); +extern X86Instr* X86Instr_Alu16 ( X86AluOp, X86Operand*, X86Operand* ); + +extern void ppX86Instr ( FILE*, X86Instr* ); + + +#endif /* ndef __X86H_DEFS_H */ diff --git a/VEX/ir_defs.c b/VEX/ir_defs.c index a4981acd02..27ca1abf68 100644 --- a/VEX/ir_defs.c +++ b/VEX/ir_defs.c @@ -6,10 +6,12 @@ /*--- ---*/ /*---------------------------------------------------------------*/ +#include +#include + #include "basictypes.h" #include "ir_defs.h" -#include /*---------------------------------------------------------------*/ /*--- Printing the IR ---*/ @@ -30,10 +32,10 @@ void ppIRType ( FILE* f, IRType ty ) void ppIRConst ( FILE* f, IRConst* con ) { switch (con->tag) { - case Ico_u8: fprintf(f, "0x%x", (UInt)(con->Ico.u8)); break; - case Ico_u16: fprintf(f, "0x%x", (UInt)(con->Ico.u16)); break; - case Ico_u32: fprintf(f, "0x%x", (UInt)(con->Ico.u32)); break; - case Ico_u64: fprintf(f, "0x%llx", (ULong)(con->Ico.u64)); break; + case Ico_U8: fprintf(f, "0x%x", (UInt)(con->Ico.U8)); break; + case Ico_U16: fprintf(f, "0x%x", (UInt)(con->Ico.U16)); break; + case Ico_U32: fprintf(f, "0x%x", (UInt)(con->Ico.U32)); break; + case Ico_U64: fprintf(f, "0x%llx", (ULong)(con->Ico.U64)); break; default: panic("ppIRConst"); } } @@ -147,9 +149,28 @@ void ppIRNext ( FILE* f, IRNext* nx ) } } +void ppIRTypeEnv ( FILE* f, IRTypeEnv* env ) { + UInt i; + for (i = 0; i < env->map_used; i++) { + if (i % 8 == 0) + fprintf(f, " "); + ppIRTemp(f, env->map[i].name); + fprintf(f, ":"); + ppIRType(f, env->map[i].type); + if (i % 8 == 7) + fprintf(f, "\n"); + else + fprintf(f, " "); + } + if (env->map_used > 0 && env->map_used % 8 != 7) + fprintf(f, "\n"); +} + + void ppIRBB ( FILE* f, IRBB* bb ) { IRStmt* s; + ppIRTypeEnv(f, bb->tyenv); for (s = bb->stmts; s; s = s->link) { fprintf(f, " "); ppIRStmt(f, s); @@ -165,22 +186,55 @@ void ppIRBB ( FILE* f, IRBB* bb ) /*--- Constructors ---*/ /*---------------------------------------------------------------*/ + +/* Constructors -- IRConst */ + +IRConst* IRConst_U8 ( UChar u8 ) +{ + IRConst* c = malloc(sizeof(IRConst)); + c->tag = Ico_U8; + c->Ico.U8 = u8; + return c; +} +IRConst* IRConst_U16 ( UShort u16 ) +{ + IRConst* c = malloc(sizeof(IRConst)); + c->tag = Ico_U16; + c->Ico.U16 = u16; + return c; +} +IRConst* IRConst_U32 ( UInt u32 ) +{ + IRConst* c = malloc(sizeof(IRConst)); + c->tag = Ico_U32; + c->Ico.U32 = u32; + return c; +} +IRConst* IRConst_U64 ( ULong u64 ) +{ + IRConst* c = malloc(sizeof(IRConst)); + c->tag = Ico_U64; + c->Ico.U64 = u64; + return c; +} + + /* Constructors -- IRExpr */ -IRExpr* mkExGet ( Int off, Int sz ) { +IRExpr* IRExpr_Get ( Int off, Int sz ) { IRExpr* e = malloc(sizeof(IRExpr)); e->tag = Iex_Get; e->Iex.Get.offset = off; e->Iex.Get.size = sz; return e; } -IRExpr* mkExTmp ( IRTemp tmp ) { +IRExpr* IRExpr_Tmp ( IRTemp tmp ) { IRExpr* e = malloc(sizeof(IRExpr)); e->tag = Iex_Tmp; e->Iex.Tmp.tmp = tmp; return e; } -IRExpr* mkExBinop ( IROp op, IRExpr* arg1, IRExpr* arg2 ) { +IRExpr* IRExpr_Binop ( IROp op, IRExpr* arg1, IRExpr* arg2 ) { IRExpr* e = malloc(sizeof(IRExpr)); e->tag = Iex_Binop; e->Iex.Binop.op = op; @@ -188,21 +242,21 @@ IRExpr* mkExBinop ( IROp op, IRExpr* arg1, IRExpr* arg2 ) { e->Iex.Binop.arg2 = arg2; return e; } -IRExpr* mkExUnop ( IROp op, IRExpr* arg ) { +IRExpr* IRExpr_Unop ( IROp op, IRExpr* arg ) { IRExpr* e = malloc(sizeof(IRExpr)); e->tag = Iex_Unop; e->Iex.Unop.op = op; e->Iex.Unop.arg = arg; return e; } -IRExpr* mkExLDle ( IRType ty, IRExpr* addr ) { +IRExpr* IRExpr_LDle ( IRType ty, IRExpr* addr ) { IRExpr* e = malloc(sizeof(IRExpr)); e->tag = Iex_LDle; e->Iex.LDle.ty = ty; e->Iex.LDle.addr = addr; return e; } -IRExpr* mkExConst ( IRConst* con ) { +IRExpr* IRExpr_Const ( IRConst* con ) { IRExpr* e = malloc(sizeof(IRExpr)); e->tag = Iex_Const; e->Iex.Const.con = con; @@ -212,24 +266,27 @@ IRExpr* mkExConst ( IRConst* con ) { /* Constructors -- IRStmt */ -IRStmt* mkStPut ( Int off, Int sz, IRExpr* value ) { +IRStmt* IRStmt_Put ( Int off, Int sz, IRExpr* value ) { IRStmt* s = malloc(sizeof(IRStmt)); s->tag = Ist_Put; + s->link = NULL; s->Ist.Put.offset = off; s->Ist.Put.size = sz; s->Ist.Put.expr = value; return s; } -IRStmt* mkStTmp ( IRTemp tmp, IRExpr* expr ) { +IRStmt* IRStmt_Tmp ( IRTemp tmp, IRExpr* expr ) { IRStmt* s = malloc(sizeof(IRStmt)); s->tag = Ist_Tmp; + s->link = NULL; s->Ist.Tmp.tmp = tmp; s->Ist.Tmp.expr = expr; return s; } -IRStmt* mkStSTle ( IRExpr* addr, IRExpr* value ) { +IRStmt* IRStmt_STle ( IRExpr* addr, IRExpr* value ) { IRStmt* s = malloc(sizeof(IRStmt)); s->tag = Ist_STle; + s->link = NULL; s->Ist.STle.addr = addr; s->Ist.STle.data = value; return s; @@ -238,7 +295,7 @@ IRStmt* mkStSTle ( IRExpr* addr, IRExpr* value ) { /* Constructors -- IRNext */ -IRNext* mkNxUJump ( IRConst* dst ) { +IRNext* IRNext_UJump ( IRConst* dst ) { IRNext* nx = malloc(sizeof(IRNext)); nx->tag = Inx_UJump; nx->Inx.UJump.dst = dst; @@ -248,13 +305,88 @@ IRNext* mkNxUJump ( IRConst* dst ) { /* Constructors -- IRBB */ -IRBB* mkIRBB ( IRStmt* stmts, IRNext* next ) { +IRBB* mk_IRBB ( IRTypeEnv* env, IRStmt* stmts, IRNext* next ) { IRBB* bb = malloc(sizeof(IRBB)); + bb->tyenv = env; bb->stmts = stmts; bb->next = next; return bb; } +/*---------------------------------------------------------------*/ +/*--- Helper functions for the IR ---*/ +/*---------------------------------------------------------------*/ + +IRTypeEnv* newIRTypeEnv ( void ) +{ + IRTypeEnv* env = malloc(sizeof(IRTypeEnv)); + env->map = NULL; + env->map_size = 0; + env->map_used = 0; + return env; +} + + +void addToIRTypeEnv ( IRTypeEnv* env, IRTemp tmp, IRType ty ) +{ + assert(env); + assert(env->map_used >= 0); + assert(env->map_size >= 0); + assert(env->map_used <= env->map_size); + if (env->map_used < env->map_size) { + env->map[env->map_used].name = tmp; + env->map[env->map_used].type = ty; + env->map_used++; + } else { + Int i; + Int new_size = env->map_size==0 ? 8 : 2*env->map_size; + IRTypeEnvMaplet* new_map = malloc(new_size * sizeof(IRTypeEnvMaplet)); + for (i = 0; i < env->map_used; i++) + new_map[i] = env->map[i]; + env->map = new_map; + env->map_size = new_size; + return addToIRTypeEnv(env, tmp, ty); + } +} + + +IRType lookupIRTypeEnv ( IRTypeEnv* env, IRTemp tmp ) +{ + Int i; + for (i = 0; i < env->map_used; i++) + if (env->map[i].name == tmp) + return env->map[i].type; + panic("lookupIRTypeEnv"); +} +IRType typeOfIRExpr ( IRTypeEnv* tyenv, IRExpr* e ) +{ + switch (e->tag) { + case Iex_Tmp: + return lookupIRTypeEnv(tyenv, e->Iex.Tmp.tmp); + case Iex_Const: + switch (e->Iex.Const.con->tag) { + case Ico_U8: return Ity_I8; + case Ico_U16: return Ity_I16; + case Ico_U32: return Ity_I32; + case Ico_U64: return Ity_I64; + default: panic("typeOfIRExpr:Iex_Const"); + } + break; + case Iex_Binop: + switch (e->Iex.Binop.op) { + case Iop_Add32: case Iop_Sub32: case Iop_Mul32: + case Iop_Or32: case Iop_And32: case Iop_Xor32: + case Iop_Shl32: case Iop_Shr32: case Iop_Sar32: + return Ity_I32; + default: break; + } + break; + default: + break; + } + ppIRExpr(stderr,e); + panic("typeOfIRExpr"); +} diff --git a/VEX/isel_x86.c b/VEX/isel_x86.c new file mode 100644 index 0000000000..93ae6a33b6 --- /dev/null +++ b/VEX/isel_x86.c @@ -0,0 +1,276 @@ + +/*---------------------------------------------------------------*/ +/*--- ---*/ +/*--- This file (isel_x86.c) is ---*/ +/*--- Copyright (c) 2004 OpenWorks LLP. All rights reserved. ---*/ +/*--- ---*/ +/*---------------------------------------------------------------*/ + +#include +#include + +#include "basictypes.h" +#include "ir_defs.h" +#include "host_regs.h" +#include "x86h_defs.h" + + +/*---------------------------------------------------------*/ +/*--- ISelEnv ---*/ +/*---------------------------------------------------------*/ + +/* This carries around: + + - A mapping from IRTemp to IRType, giving the type of any IRTemp we + might encounter. This is computed before insn selection starts, + and does not change. + + - A mapping from IRTemp to HReg. This tells the insn selector + which virtual register is associated with each IRTemp temporary. + This is computed before insn selection starts, and does not + change. We expect this mapping to map precisely the same set + of IRTemps as the type mapping does. + + - The code array, that is, the insns selected so far. + + - A counter, for generating new virtual registers. + + Note, this is all host-independent. +*/ + +typedef + struct { + IRTemp ir_name; + HReg vreg; + } + VRegMaplet; + +typedef + struct { + IRTypeEnv* type_env; + + VRegMaplet* vregmap; + Int n_vregmap; + + void** code; /* really, X86Instr**, or ArmInstr**, or whatever */ + Int code_size; + Int code_used; + + Int ctr; + } + ISelEnv; + + +static HReg lookupIRTemp ( ISelEnv* env, IRTemp tmp ) +{ + Int i; + for (i = 0; i < env->n_vregmap; i++) + if (env->vregmap[i].ir_name == tmp) + return env->vregmap[i].vreg; + panic("lookupIRTemp"); +} + +static void addInstr ( ISelEnv* env, void* instr ) +{ + assert(env->code_used < env->code_size); + env->code[env->code_used++] = instr; + ppX86Instr(stdout, instr); + printf("\n"); +} + +static HReg newVRegI ( ISelEnv* env ) +{ + HReg reg = mkHReg(env->ctr, HRcInt, True/*virtual reg*/); + env->ctr++; + return reg; +} + + +/*---------------------------------------------------------*/ +/*--- ISEL: Integer expressions ---*/ +/*---------------------------------------------------------*/ + +/* Select insns for an integer-typed expression, and add them to the + code list. Return a vreg holding the result. The vreg MUST NOT BE + MODIFIED. If you want to modify it, ask for a new vreg, copy it in + there, and modify the copy. The register allocator will do its + best to map both vregs to the same real register, so the copies + will often disappear later in the game. +*/ +HReg iselExprI ( ISelEnv* env, IRExpr* e ) +{ + assert(e); + assert(typeOfIRExpr(env->type_env,e) == Ity_I32); + + switch (e->tag) { + + case Iex_Tmp: + return lookupIRTemp(env, e->Iex.Tmp.tmp); + + case Iex_Binop: + /* Add32(x,y) */ + if (e->Iex.Binop.op == Iop_Add32) { + HReg res = newVRegI(env); + HReg src = iselExprI(env, e->Iex.Binop.arg1); + HReg dst = iselExprI(env, e->Iex.Binop.arg2); + addInstr(env, X86Instr_Mov32( + X86Operand_Reg(dst), + X86Operand_Reg(res))); + addInstr(env, X86Instr_Alu32( + Xalu_ADD, X86Operand_Reg(src), + X86Operand_Reg(res)) ); + return res; + } + + /* 32-bit literals */ + case Iex_Const: { + switch (e->Iex.Const.con->tag) { + case Ico_U32: { + HReg r = newVRegI(env); + addInstr(env, + X86Instr_Mov32(X86Operand_Imm(e->Iex.Const.con->Ico.U32), + X86Operand_Reg(r))); + return r; + } + default: break; + } + } + + default: + break; + } /* switch (e->tag) */ + + /* We get here if no pattern matched. */ + ppIRExpr(stderr, e); + panic("iselExprI: cannot reduce tree"); +} + + +/* Similarly, return an AMode which computes the value of the + specified expression, possibly also adding insns to the code list + as a result. +*/ +X86AMode* iselAMode ( ISelEnv* env, IRExpr* e ) +{ + assert(e); + assert(typeOfIRExpr(env->type_env,e) == Ity_I32); + + /* Add32(expr1, Shl32(expr2, imm)) */ + if (e->tag == Iex_Binop + && e->Iex.Binop.op == Iop_Add32 + && e->Iex.Binop.arg2->tag == Iex_Binop + && e->Iex.Binop.arg2->Iex.Binop.op == Iop_Shl32 + && e->Iex.Binop.arg2->Iex.Binop.arg2->tag == Iex_Const + && e->Iex.Binop.arg2->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32) { + UInt shift = e->Iex.Binop.arg2->Iex.Binop.arg2->Iex.Const.con->Ico.U32; + if (shift == 2 || shift == 4 || shift == 8) { + HReg r1 = iselExprI(env, e->Iex.Binop.arg1); + HReg r2 = iselExprI(env, e->Iex.Binop.arg2->Iex.Binop.arg1 ); + return X86AMode_IRRS(0, r1, r2, shift); + } + } + + /* Add32(expr,i) */ + if (e->tag == Iex_Binop + && e->Iex.Binop.op == Iop_Add32 + && e->Iex.Binop.arg2->tag == Iex_Const + && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32) { + HReg r1 = iselExprI(env, e->Iex.Binop.arg1); + return X86AMode_IR(r1, e->Iex.Binop.arg2->Iex.Const.con->Ico.U32); + } + + /* Doesn't match anything in particular. Generate it into + a register and use that. */ + { + HReg r1 = iselExprI(env, e); + return X86AMode_IR(r1, 0); + } +} + + +/*---------------------------------------------------------*/ +/*--- ISEL: Statements ---*/ +/*---------------------------------------------------------*/ + +void iselStmt ( ISelEnv* env, IRStmt* stmt ) +{ + switch (stmt->tag) { + + case Ist_Put: + if (stmt->Ist.Put.size == 4) { + HReg ebp = mkHReg(5, HRcInt, False); + HReg reg = iselExprI(env, stmt->Ist.Put.expr); + addInstr(env, + X86Instr_ST32(reg, + X86AMode_IR(stmt->Ist.Put.offset, + ebp) + )); + return; + } + + default: break; + } + ppIRStmt(stderr, stmt); + panic("iselStmt"); +} + + +/*---------------------------------------------------------*/ +/*--- ISEL: Basic block terminators (Nexts) ---*/ +/*---------------------------------------------------------*/ + +void iselNext ( ISelEnv* env, IRNext* next ) +{ + switch (next->tag) { + default: + ppIRNext(stderr, next); + panic("iselNext"); + } +} + + +/*---------------------------------------------------------*/ +/*--- Insn selector top-level ---*/ +/*---------------------------------------------------------*/ + +void /* not really, but for the time being ... */ + iselBB ( IRBB* bb ) +{ + Int i; + HReg hreg; + IRStmt* stmt; + + /* Make up an initial environment to use. */ + ISelEnv* env = malloc(sizeof(ISelEnv)); + env->ctr = 0; + + /* Set up output code array. */ + env->code_used = 0; + env->code_size = 40; + env->code = malloc(env->code_size * sizeof(void*)); + + /* Copy BB's type env. */ + env->type_env = bb->tyenv; + + /* Make up an IRTemp -> virtual HReg mapping. This doesn't + change as we go along. */ + env->n_vregmap = bb->tyenv->map_used; + env->vregmap = malloc(env->n_vregmap * sizeof(VRegMaplet)); + + /* For each IR temporary, allocate a suitably-kinded virtual + register. */ + for (i = 0; i < env->n_vregmap; i++) { + env->vregmap[i].ir_name = bb->tyenv->map[i].name; + switch (bb->tyenv->map[i].type) { + case Ity_I32: hreg = mkHReg(i, HRcInt, True); break; + default: panic("iselBB: IRTemp type"); + } + env->vregmap[i].vreg = hreg; + } + + /* Ok, finally we can iterate over the statements. */ + for (stmt = bb->stmts; stmt; stmt=stmt->link) + iselStmt(env,stmt); + + iselNext(env,bb->next); +} diff --git a/VEX/test_main.c b/VEX/test_main.c new file mode 100644 index 0000000000..4af4155459 --- /dev/null +++ b/VEX/test_main.c @@ -0,0 +1,54 @@ + +/*---------------------------------------------------------------*/ +/*--- ---*/ +/*--- This file (test_main.c) is ---*/ +/*--- Copyright (c) 2004 OpenWorks LLP. All rights reserved. ---*/ +/*--- ---*/ +/*---------------------------------------------------------------*/ + +#include +#include + +#include "basictypes.h" +#include "ir_defs.h" + + + + + +/*---------------------------------------------------------------*/ +/*--- Test ---*/ +/*---------------------------------------------------------------*/ + +/* HACK */ +extern +void /* not really, but for the time being ... */ + iselBB ( IRBB* bb ); + +int main ( void ) +{ + IRBB* bb; + IRTypeEnv* env = newIRTypeEnv(); + + IRTemp t1 = 1; + IRTemp t2 = 2; + + addToIRTypeEnv ( env, t1, Ity_I32 ); + addToIRTypeEnv ( env, t2, Ity_I32 ); + + IRStmt* s1 = IRStmt_Put(8,4, IRExpr_Const(IRConst_U32(99)) ); + IRStmt* s2 = IRStmt_Put(7,4, IRExpr_Binop(Iop_Add32, + IRExpr_Tmp(t1), + IRExpr_Const(IRConst_U32(55)))); + s1->link = s2; + + bb = mk_IRBB(env, s1, IRNext_UJump(IRConst_U32(-65565))); + + printf("bb is ...\n"); + ppIRBB(stdout, bb); + printf("\n"); + + iselBB(bb); + + return 0; +} diff --git a/VEX/x86h_defs.c b/VEX/x86h_defs.c new file mode 100644 index 0000000000..0f3549a84a --- /dev/null +++ b/VEX/x86h_defs.c @@ -0,0 +1,226 @@ + +/*---------------------------------------------------------------*/ +/*--- ---*/ +/*--- This file (x86h_defs.c) is ---*/ +/*--- Copyright (c) 2004 OpenWorks LLP. All rights reserved. ---*/ +/*--- ---*/ +/*---------------------------------------------------------------*/ + +#include +#include + +#include "basictypes.h" +#include "host_regs.h" +#include "x86h_defs.h" + + +/* --------- Registers. --------- */ + +void ppHRegX86 ( FILE* f, HReg reg ) +{ + Int r; + static Char* ireg32_names[8] + = { "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi" }; + /* Be generic for all virtual regs. */ + if (hregIsVirtual(reg)) { + ppHReg(f, reg); + return; + } + /* But specific for real regs. */ + switch (hregClass(reg)) { + case HRcInt: + r = hregNumber(reg); + assert(r >= 0 && r < 8); + fprintf(f, "%s", ireg32_names[r]); + return; + case HRcFloat: + r = hregNumber(reg); + assert(r >= 0 && r < 6); + fprintf(f, "%%fake%d", r); + return; + case HRcVector: + panic("ppHRegX86: real vector reg"); + default: + panic("ppHRegX86"); + } +} + + +/* --------- X86AMode: memory address expressions. --------- */ + +X86AMode* X86AMode_IR ( UInt imm32, HReg reg ) { + X86AMode* am = malloc(sizeof(X86AMode)); + am->tag = Xam_IR; + am->Xam.IR.imm = imm32; + am->Xam.IR.reg = reg; + return am; +} + +X86AMode* X86AMode_IRRS ( UInt imm32, HReg base, HReg index, Int shift ) { + X86AMode* am = malloc(sizeof(X86AMode)); + am->tag = Xam_IRRS; + am->Xam.IRRS.imm = imm32; + am->Xam.IRRS.base = base; + am->Xam.IRRS.index = index; + am->Xam.IRRS.shift = shift; + assert(shift >= 0 && shift <= 3); + return am; +} + +void ppX86AMode ( FILE* f, X86AMode* am ) { + switch (am->tag) { + case Xam_IR: + fprintf(f, "0x%x(", am->Xam.IR.imm); + ppHRegX86(f, am->Xam.IR.reg); + fprintf(f, ")"); + return; + case Xam_IRRS: + fprintf(f, "0x%x(", am->Xam.IRRS.imm); + ppHRegX86(f, am->Xam.IRRS.base); + fprintf(f, ","); + ppHRegX86(f, am->Xam.IRRS.index); + fprintf(f, ",%d)", am->Xam.IRRS.shift); + return; + default: + panic("ppX86AMode"); + } +} + + +/* --------- X86Operand. Not all are valid for all insns. --------- */ + +X86Operand* X86Operand_Imm ( UInt imm32 ) { + X86Operand* op = malloc(sizeof(X86Operand)); + op->tag = Xop_Imm; + op->Xop.Imm.imm32 = imm32; + return op; +} + +X86Operand* X86Operand_Reg ( HReg reg ) { + X86Operand* op = malloc(sizeof(X86Operand)); + op->tag = Xop_Reg; + op->Xop.Reg.reg = reg; + return op; +} + +X86Operand* X86Operand_Mem ( X86AMode* am ) { + X86Operand* op = malloc(sizeof(X86Operand)); + op->tag = Xop_Mem; + op->Xop.Mem.am = am; + return op; +} + +void ppX86Operand ( FILE* f, X86Operand* op ) { + switch (op->tag) { + case Xop_Imm: + fprintf(f, "$0x%x", op->Xop.Imm.imm32); + return; + case Xop_Reg: + ppHRegX86(f, op->Xop.Reg.reg); + return; + case Xop_Mem: + ppX86AMode(f, op->Xop.Mem.am); + return; + default: + panic("ppX86Operand"); + } +} + + +/* --------- Instructions. --------- */ + +void ppX86AluOp ( FILE* f, X86AluOp op ) { + Char* name; + switch (op) { + case Xalu_ADD: name = "add"; break; + case Xalu_SUB: name = "sub"; break; + case Xalu_ADC: name = "adc"; break; + case Xalu_SBB: name = "sbb"; break; + case Xalu_AND: name = "and"; break; + case Xalu_OR: name = "or"; break; + case Xalu_XOR: name = "xor"; break; + default: panic("ppX86AluOp"); + } + fprintf(f, "%s", name); +} + +X86Instr* X86Instr_ST32 ( HReg src, X86AMode* dst ) { + X86Instr* i = malloc(sizeof(X86Instr)); + i->tag = Xin_ST32; + i->Xin.ST32.src = src; + i->Xin.ST32.dst = dst; + return i; +} + +X86Instr* X86Instr_LD32 ( X86AMode* src, HReg dst ) { + X86Instr* i = malloc(sizeof(X86Instr)); + i->tag = Xin_LD32; + i->Xin.LD32.src = src; + i->Xin.LD32.dst = dst; + return i; +} + +X86Instr* X86Instr_Alu32 ( X86AluOp op, X86Operand* src, X86Operand* dst ) { + X86Instr* i = malloc(sizeof(X86Instr)); + i->tag = Xin_Alu32; + i->Xin.Alu32.op = op; + i->Xin.Alu32.src = src; + i->Xin.Alu32.dst = dst; + return i; +} + +X86Instr* X86Instr_Mov32 ( X86Operand* src, X86Operand* dst ) { + X86Instr* i = malloc(sizeof(X86Instr)); + i->tag = Xin_Mov32; + i->Xin.Mov32.src = src; + i->Xin.Mov32.dst = dst; + return i; +} + +X86Instr* X86Instr_Alu16 ( X86AluOp op, X86Operand* src, X86Operand* dst ) { + X86Instr* i = malloc(sizeof(X86Instr)); + i->tag = Xin_Alu16; + i->Xin.Alu16.op = op; + i->Xin.Alu16.src = src; + i->Xin.Alu16.dst = dst; + return i; +} + +void ppX86Instr ( FILE* f, X86Instr* i ) { + switch (i->tag) { + case Xin_ST32: + fprintf(f, "movl "); + ppHRegX86(f, i->Xin.ST32.src); + fprintf(f, ","); + ppX86AMode(f, i->Xin.ST32.dst); + return; + case Xin_LD32: + fprintf(f, "movl "); + ppX86AMode(f, i->Xin.LD32.src); + fprintf(f, ","); + ppHRegX86(f, i->Xin.LD32.dst); + return; + case Xin_Alu32: + ppX86AluOp(f, i->Xin.Alu32.op); + fprintf(f, "l "); + ppX86Operand(f, i->Xin.Alu32.src); + fprintf(f, ","); + ppX86Operand(f, i->Xin.Alu32.dst); + return; + case Xin_Mov32: + fprintf(f, "movl "); + ppX86Operand(f, i->Xin.Mov32.src); + fprintf(f, ","); + ppX86Operand(f, i->Xin.Mov32.dst); + return; + case Xin_Alu16: + ppX86AluOp(f, i->Xin.Alu16.op); + fprintf(f, "w "); + ppX86Operand(f, i->Xin.Alu16.src); + fprintf(f, ","); + ppX86Operand(f, i->Xin.Alu16.dst); + return; + default: + panic("ppX86Instr"); + } +}