-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
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)
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
+
--- /dev/null
+
+/*---------------------------------------------------------------*/
+/*--- ---*/
+/*--- This file (host_regs.c) is ---*/
+/*--- Copyright (c) 2004 OpenWorks LLP. All rights reserved. ---*/
+/*--- ---*/
+/*---------------------------------------------------------------*/
+
+#include <stdio.h>
+
+#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");
+ }
+}
+
--- /dev/null
+
+/*---------------------------------------------------------------*/
+/*--- ---*/
+/*--- 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 */
#ifndef __IR_DEFS_H
#define __IR_DEFS_H
-#include <stdio.h> /* 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,
}
IROp;
+extern void ppIROp ( FILE* f, IROp );
-/* Expressions
+/* ------------------ Expressions ------------------ */
+/*
data Expr
= GET Int Int -- offset, size
| TMP Temp -- value of temporary
}
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
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.
}
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 */
--- /dev/null
+
+/*---------------------------------------------------------------*/
+/*--- ---*/
+/*--- 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 */
/*--- ---*/
/*---------------------------------------------------------------*/
+#include <stdio.h>
+#include <malloc.h>
+
#include "basictypes.h"
#include "ir_defs.h"
-#include <malloc.h>
/*---------------------------------------------------------------*/
/*--- Printing the IR ---*/
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");
}
}
}
}
+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);
/*--- 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;
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;
/* 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;
/* 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;
/* 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");
+}
--- /dev/null
+
+/*---------------------------------------------------------------*/
+/*--- ---*/
+/*--- This file (isel_x86.c) is ---*/
+/*--- Copyright (c) 2004 OpenWorks LLP. All rights reserved. ---*/
+/*--- ---*/
+/*---------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <malloc.h>
+
+#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);
+}
--- /dev/null
+
+/*---------------------------------------------------------------*/
+/*--- ---*/
+/*--- This file (test_main.c) is ---*/
+/*--- Copyright (c) 2004 OpenWorks LLP. All rights reserved. ---*/
+/*--- ---*/
+/*---------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#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;
+}
--- /dev/null
+
+/*---------------------------------------------------------------*/
+/*--- ---*/
+/*--- This file (x86h_defs.c) is ---*/
+/*--- Copyright (c) 2004 OpenWorks LLP. All rights reserved. ---*/
+/*--- ---*/
+/*---------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <malloc.h>
+
+#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");
+ }
+}