From: Cerion Armour-Brown Date: Fri, 4 Feb 2005 16:17:07 +0000 (+0000) Subject: Get the PPC32 back-end show on the road. X-Git-Tag: svn/VALGRIND_3_0_1^2~497 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=b9345ff7689869a41830ebbab00f812431994233;p=thirdparty%2Fvalgrind.git Get the PPC32 back-end show on the road. git-svn-id: svn://svn.valgrind.org/vex/trunk@837 --- diff --git a/VEX/Makefile b/VEX/Makefile index 634469c112..38ecee2374 100644 --- a/VEX/Makefile +++ b/VEX/Makefile @@ -12,6 +12,7 @@ PUB_HEADERS = pub/libvex_basictypes.h \ PRIV_HEADERS = priv/host-x86/hdefs.h \ priv/host-amd64/hdefs.h \ priv/host-arm/hdefs.h \ + priv/host-ppc32/hdefs.h \ priv/host-generic/h_generic_regs.h \ priv/host-generic/h_generic_simd64.h \ priv/main/vex_globals.h \ @@ -32,9 +33,11 @@ LIB_OBJS = priv/ir/irdefs.o \ priv/host-x86/hdefs.o \ priv/host-amd64/hdefs.o \ priv/host-arm/hdefs.o \ + priv/host-ppc32/hdefs.o \ priv/host-x86/isel.o \ priv/host-amd64/isel.o \ priv/host-arm/isel.o \ + priv/host-ppc32/isel.o \ priv/host-generic/h_generic_regs.o \ priv/host-generic/h_generic_simd64.o \ priv/host-generic/reg_alloc2.o \ @@ -148,6 +151,10 @@ priv/host-arm/hdefs.o: $(ALL_HEADERS) priv/host-arm/hdefs.c $(CC) $(CCFLAGS) $(ALL_INCLUDES) -o priv/host-arm/hdefs.o \ -c priv/host-arm/hdefs.c +priv/host-ppc32/hdefs.o: $(ALL_HEADERS) priv/host-ppc32/hdefs.c + $(CC) $(CCFLAGS) $(ALL_INCLUDES) -o priv/host-ppc32/hdefs.o \ + -c priv/host-ppc32/hdefs.c + priv/host-x86/isel.o: $(ALL_HEADERS) priv/host-x86/isel.c $(CC) $(CCFLAGS) $(ALL_INCLUDES) -o priv/host-x86/isel.o \ -c priv/host-x86/isel.c @@ -160,6 +167,10 @@ priv/host-arm/isel.o: $(ALL_HEADERS) priv/host-arm/isel.c $(CC) $(CCFLAGS) $(ALL_INCLUDES) -o priv/host-arm/isel.o \ -c priv/host-arm/isel.c +priv/host-ppc32/isel.o: $(ALL_HEADERS) priv/host-ppc32/isel.c + $(CC) $(CCFLAGS) $(ALL_INCLUDES) -o priv/host-ppc32/isel.o \ + -c priv/host-ppc32/isel.c + priv/host-generic/h_generic_regs.o: $(ALL_HEADERS) priv/host-generic/h_generic_regs.c $(CC) $(CCFLAGS) $(ALL_INCLUDES) -o priv/host-generic/h_generic_regs.o \ -c priv/host-generic/h_generic_regs.c diff --git a/VEX/Makefile-icc b/VEX/Makefile-icc index 5595b9dc8d..8280234b04 100644 --- a/VEX/Makefile-icc +++ b/VEX/Makefile-icc @@ -12,6 +12,7 @@ PUB_HEADERS = pub/libvex_basictypes.h \ PRIV_HEADERS = priv/host-x86/hdefs.h \ priv/host-amd64/hdefs.h \ priv/host-arm/hdefs.h \ + priv/host-ppc32/hdefs.h \ priv/host-generic/h_generic_regs.h \ priv/host-generic/h_generic_simd64.h \ priv/main/vex_globals.h \ @@ -32,9 +33,11 @@ LIB_OBJS = priv/ir/irdefs.o \ priv/host-x86/hdefs.o \ priv/host-amd64/hdefs.o \ priv/host-arm/hdefs.o \ + priv/host-ppc32/hdefs.o \ priv/host-x86/isel.o \ priv/host-amd64/isel.o \ priv/host-arm/isel.o \ + priv/host-ppc32/isel.o \ priv/host-generic/h_generic_regs.o \ priv/host-generic/h_generic_simd64.o \ priv/host-generic/reg_alloc2.o \ @@ -148,6 +151,10 @@ priv/host-arm/hdefs.o: $(ALL_HEADERS) priv/host-arm/hdefs.c $(CC) $(CCFLAGS) $(ALL_INCLUDES) -o priv/host-arm/hdefs.o \ -c priv/host-arm/hdefs.c +priv/host-ppc32/hdefs.o: $(ALL_HEADERS) priv/host-ppc32/hdefs.c + $(CC) $(CCFLAGS) $(ALL_INCLUDES) -o priv/host-ppc32/hdefs.o \ + -c priv/host-ppc32/hdefs.c + priv/host-x86/isel.o: $(ALL_HEADERS) priv/host-x86/isel.c $(CC) $(CCFLAGS) $(ALL_INCLUDES) -o priv/host-x86/isel.o \ -c priv/host-x86/isel.c @@ -160,6 +167,10 @@ priv/host-arm/isel.o: $(ALL_HEADERS) priv/host-arm/isel.c $(CC) $(CCFLAGS) $(ALL_INCLUDES) -o priv/host-arm/isel.o \ -c priv/host-arm/isel.c +priv/host-ppc32/isel.o: $(ALL_HEADERS) priv/host-ppc32/isel.c + $(CC) $(CCFLAGS) $(ALL_INCLUDES) -o priv/host-ppc32/isel.o \ + -c priv/host-ppc32/isel.c + priv/host-generic/h_generic_regs.o: $(ALL_HEADERS) priv/host-generic/h_generic_regs.c $(CC) $(CCFLAGS) $(ALL_INCLUDES) -o priv/host-generic/h_generic_regs.o \ -c priv/host-generic/h_generic_regs.c diff --git a/VEX/priv/host-ppc32/hdefs.c b/VEX/priv/host-ppc32/hdefs.c new file mode 100644 index 0000000000..f100f6183e --- /dev/null +++ b/VEX/priv/host-ppc32/hdefs.c @@ -0,0 +1,2862 @@ + +/*---------------------------------------------------------------*/ +/*--- ---*/ +/*--- This file (host-ppc32/hdefs.c) is ---*/ +/*--- Copyright (c) 2005 OpenWorks LLP. All rights reserved. ---*/ +/*--- ---*/ +/*---------------------------------------------------------------*/ + +/* + This file is part of LibVEX, a library for dynamic binary + instrumentation and translation. + + Copyright (C) 2004-2005 OpenWorks, LLP. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; Version 2 dated June 1991 of the + license. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or liability + for damages. See the GNU General Public License for more details. + + Neither the names of the U.S. Department of Energy nor the + University of California nor the names of its contributors may be + used to endorse or promote products derived from this software + without prior written permission. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +*/ + +#include "libvex_basictypes.h" +#include "libvex.h" +#include "libvex_trc_values.h" + +#include "main/vex_util.h" +#include "host-generic/h_generic_regs.h" +#include "host-ppc32/hdefs.h" + + +/* --------- Registers. --------- */ + +void ppHRegPPC32 ( HReg reg ) +{ vassert(0); +//.. Int r; +//.. static HChar* ireg32_names[8] +//.. = { "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi" }; +//.. /* Be generic for all virtual regs. */ +//.. if (hregIsVirtual(reg)) { +//.. ppHReg(reg); +//.. return; +//.. } +//.. /* But specific for real regs. */ +//.. switch (hregClass(reg)) { +//.. case HRcInt32: +//.. r = hregNumber(reg); +//.. vassert(r >= 0 && r < 8); +//.. vex_printf("%s", ireg32_names[r]); +//.. return; +//.. case HRcFlt64: +//.. r = hregNumber(reg); +//.. vassert(r >= 0 && r < 6); +//.. vex_printf("%%fake%d", r); +//.. return; +//.. case HRcVec128: +//.. r = hregNumber(reg); +//.. vassert(r >= 0 && r < 8); +//.. vex_printf("%%xmm%d", r); +//.. return; +//.. default: +//.. vpanic("ppHRegX86"); +//.. } +} + +//.. HReg hregX86_EAX ( void ) { return mkHReg(0, HRcInt32, False); } +//.. HReg hregX86_ECX ( void ) { return mkHReg(1, HRcInt32, False); } +//.. HReg hregX86_EDX ( void ) { return mkHReg(2, HRcInt32, False); } +//.. HReg hregX86_EBX ( void ) { return mkHReg(3, HRcInt32, False); } +//.. HReg hregX86_ESP ( void ) { return mkHReg(4, HRcInt32, False); } +//.. HReg hregX86_EBP ( void ) { return mkHReg(5, HRcInt32, False); } +//.. HReg hregX86_ESI ( void ) { return mkHReg(6, HRcInt32, False); } +//.. HReg hregX86_EDI ( void ) { return mkHReg(7, HRcInt32, False); } +//.. +//.. HReg hregX86_FAKE0 ( void ) { return mkHReg(0, HRcFlt64, False); } +//.. HReg hregX86_FAKE1 ( void ) { return mkHReg(1, HRcFlt64, False); } +//.. HReg hregX86_FAKE2 ( void ) { return mkHReg(2, HRcFlt64, False); } +//.. HReg hregX86_FAKE3 ( void ) { return mkHReg(3, HRcFlt64, False); } +//.. HReg hregX86_FAKE4 ( void ) { return mkHReg(4, HRcFlt64, False); } +//.. HReg hregX86_FAKE5 ( void ) { return mkHReg(5, HRcFlt64, False); } +//.. +//.. HReg hregX86_XMM0 ( void ) { return mkHReg(0, HRcVec128, False); } +//.. HReg hregX86_XMM1 ( void ) { return mkHReg(1, HRcVec128, False); } +//.. HReg hregX86_XMM2 ( void ) { return mkHReg(2, HRcVec128, False); } +//.. HReg hregX86_XMM3 ( void ) { return mkHReg(3, HRcVec128, False); } +//.. HReg hregX86_XMM4 ( void ) { return mkHReg(4, HRcVec128, False); } +//.. HReg hregX86_XMM5 ( void ) { return mkHReg(5, HRcVec128, False); } +//.. HReg hregX86_XMM6 ( void ) { return mkHReg(6, HRcVec128, False); } +//.. HReg hregX86_XMM7 ( void ) { return mkHReg(7, HRcVec128, False); } + + +void getAllocableRegs_PPC32 ( Int* nregs, HReg** arr ) +{ *nregs= 0; *arr=NULL; +//.. *nregs = 20; +//.. *arr = LibVEX_Alloc(*nregs * sizeof(HReg)); +//.. (*arr)[0] = hregX86_EAX(); +//.. (*arr)[1] = hregX86_EBX(); +//.. (*arr)[2] = hregX86_ECX(); +//.. (*arr)[3] = hregX86_EDX(); +//.. (*arr)[4] = hregX86_ESI(); +//.. (*arr)[5] = hregX86_EDI(); +//.. (*arr)[6] = hregX86_FAKE0(); +//.. (*arr)[7] = hregX86_FAKE1(); +//.. (*arr)[8] = hregX86_FAKE2(); +//.. (*arr)[9] = hregX86_FAKE3(); +//.. (*arr)[10] = hregX86_FAKE4(); +//.. (*arr)[11] = hregX86_FAKE5(); +//.. (*arr)[12] = hregX86_XMM0(); +//.. (*arr)[13] = hregX86_XMM1(); +//.. (*arr)[14] = hregX86_XMM2(); +//.. (*arr)[15] = hregX86_XMM3(); +//.. (*arr)[16] = hregX86_XMM4(); +//.. (*arr)[17] = hregX86_XMM5(); +//.. (*arr)[18] = hregX86_XMM6(); +//.. (*arr)[19] = hregX86_XMM7(); +} + + +//.. /* --------- Condition codes, Intel encoding. --------- */ +//.. +//.. HChar* showX86CondCode ( X86CondCode cond ) +//.. { +//.. switch (cond) { +//.. case Xcc_O: return "o"; +//.. case Xcc_NO: return "no"; +//.. case Xcc_B: return "b"; +//.. case Xcc_NB: return "nb"; +//.. case Xcc_Z: return "z"; +//.. case Xcc_NZ: return "nz"; +//.. case Xcc_BE: return "be"; +//.. case Xcc_NBE: return "nbe"; +//.. case Xcc_S: return "s"; +//.. case Xcc_NS: return "ns"; +//.. case Xcc_P: return "p"; +//.. case Xcc_NP: return "np"; +//.. case Xcc_L: return "l"; +//.. case Xcc_NL: return "nl"; +//.. case Xcc_LE: return "le"; +//.. case Xcc_NLE: return "nle"; +//.. case Xcc_ALWAYS: return "ALWAYS"; +//.. default: vpanic("ppX86CondCode"); +//.. } +//.. } +//.. +//.. +//.. /* --------- X86AMode: memory address expressions. --------- */ +//.. +//.. X86AMode* X86AMode_IR ( UInt imm32, HReg reg ) { +//.. X86AMode* am = LibVEX_Alloc(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 = LibVEX_Alloc(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; +//.. vassert(shift >= 0 && shift <= 3); +//.. return am; +//.. } +//.. +//.. X86AMode* dopyX86AMode ( X86AMode* am ) { +//.. switch (am->tag) { +//.. case Xam_IR: +//.. return X86AMode_IR( am->Xam.IR.imm, am->Xam.IR.reg ); +//.. case Xam_IRRS: +//.. return X86AMode_IRRS( am->Xam.IRRS.imm, am->Xam.IRRS.base, +//.. am->Xam.IRRS.index, am->Xam.IRRS.shift ); +//.. default: +//.. vpanic("dopyX86AMode"); +//.. } +//.. } +//.. +//.. void ppX86AMode ( X86AMode* am ) { +//.. switch (am->tag) { +//.. case Xam_IR: +//.. if (am->Xam.IR.imm == 0) +//.. vex_printf("("); +//.. else +//.. vex_printf("0x%x(", am->Xam.IR.imm); +//.. ppHRegX86(am->Xam.IR.reg); +//.. vex_printf(")"); +//.. return; +//.. case Xam_IRRS: +//.. vex_printf("0x%x(", am->Xam.IRRS.imm); +//.. ppHRegX86(am->Xam.IRRS.base); +//.. vex_printf(","); +//.. ppHRegX86(am->Xam.IRRS.index); +//.. vex_printf(",%d)", 1 << am->Xam.IRRS.shift); +//.. return; +//.. default: +//.. vpanic("ppX86AMode"); +//.. } +//.. } +//.. +//.. static void addRegUsage_X86AMode ( HRegUsage* u, X86AMode* am ) { +//.. switch (am->tag) { +//.. case Xam_IR: +//.. addHRegUse(u, HRmRead, am->Xam.IR.reg); +//.. return; +//.. case Xam_IRRS: +//.. addHRegUse(u, HRmRead, am->Xam.IRRS.base); +//.. addHRegUse(u, HRmRead, am->Xam.IRRS.index); +//.. return; +//.. default: +//.. vpanic("addRegUsage_X86AMode"); +//.. } +//.. } +//.. +//.. static void mapRegs_X86AMode ( HRegRemap* m, X86AMode* am ) { +//.. switch (am->tag) { +//.. case Xam_IR: +//.. am->Xam.IR.reg = lookupHRegRemap(m, am->Xam.IR.reg); +//.. return; +//.. case Xam_IRRS: +//.. am->Xam.IRRS.base = lookupHRegRemap(m, am->Xam.IRRS.base); +//.. am->Xam.IRRS.index = lookupHRegRemap(m, am->Xam.IRRS.index); +//.. return; +//.. default: +//.. vpanic("mapRegs_X86AMode"); +//.. } +//.. } +//.. +//.. /* --------- Operand, which can be reg, immediate or memory. --------- */ +//.. +//.. X86RMI* X86RMI_Imm ( UInt imm32 ) { +//.. X86RMI* op = LibVEX_Alloc(sizeof(X86RMI)); +//.. op->tag = Xrmi_Imm; +//.. op->Xrmi.Imm.imm32 = imm32; +//.. return op; +//.. } +//.. X86RMI* X86RMI_Reg ( HReg reg ) { +//.. X86RMI* op = LibVEX_Alloc(sizeof(X86RMI)); +//.. op->tag = Xrmi_Reg; +//.. op->Xrmi.Reg.reg = reg; +//.. return op; +//.. } +//.. X86RMI* X86RMI_Mem ( X86AMode* am ) { +//.. X86RMI* op = LibVEX_Alloc(sizeof(X86RMI)); +//.. op->tag = Xrmi_Mem; +//.. op->Xrmi.Mem.am = am; +//.. return op; +//.. } +//.. +//.. void ppX86RMI ( X86RMI* op ) { +//.. switch (op->tag) { +//.. case Xrmi_Imm: +//.. vex_printf("$0x%x", op->Xrmi.Imm.imm32); +//.. return; +//.. case Xrmi_Reg: +//.. ppHRegX86(op->Xrmi.Reg.reg); +//.. return; +//.. case Xrmi_Mem: +//.. ppX86AMode(op->Xrmi.Mem.am); +//.. return; +//.. default: +//.. vpanic("ppX86RMI"); +//.. } +//.. } +//.. +//.. /* An X86RMI can only be used in a "read" context (what would it mean +//.. to write or modify a literal?) and so we enumerate its registers +//.. accordingly. */ +//.. static void addRegUsage_X86RMI ( HRegUsage* u, X86RMI* op ) { +//.. switch (op->tag) { +//.. case Xrmi_Imm: +//.. return; +//.. case Xrmi_Reg: +//.. addHRegUse(u, HRmRead, op->Xrmi.Reg.reg); +//.. return; +//.. case Xrmi_Mem: +//.. addRegUsage_X86AMode(u, op->Xrmi.Mem.am); +//.. return; +//.. default: +//.. vpanic("addRegUsage_X86RMI"); +//.. } +//.. } +//.. +//.. static void mapRegs_X86RMI ( HRegRemap* m, X86RMI* op ) { +//.. switch (op->tag) { +//.. case Xrmi_Imm: +//.. return; +//.. case Xrmi_Reg: +//.. op->Xrmi.Reg.reg = lookupHRegRemap(m, op->Xrmi.Reg.reg); +//.. return; +//.. case Xrmi_Mem: +//.. mapRegs_X86AMode(m, op->Xrmi.Mem.am); +//.. return; +//.. default: +//.. vpanic("mapRegs_X86RMI"); +//.. } +//.. } +//.. +//.. +//.. /* --------- Operand, which can be reg or immediate only. --------- */ +//.. +//.. X86RI* X86RI_Imm ( UInt imm32 ) { +//.. X86RI* op = LibVEX_Alloc(sizeof(X86RI)); +//.. op->tag = Xri_Imm; +//.. op->Xri.Imm.imm32 = imm32; +//.. return op; +//.. } +//.. X86RI* X86RI_Reg ( HReg reg ) { +//.. X86RI* op = LibVEX_Alloc(sizeof(X86RI)); +//.. op->tag = Xri_Reg; +//.. op->Xri.Reg.reg = reg; +//.. return op; +//.. } +//.. +//.. void ppX86RI ( X86RI* op ) { +//.. switch (op->tag) { +//.. case Xri_Imm: +//.. vex_printf("$0x%x", op->Xri.Imm.imm32); +//.. return; +//.. case Xri_Reg: +//.. ppHRegX86(op->Xri.Reg.reg); +//.. return; +//.. default: +//.. vpanic("ppX86RI"); +//.. } +//.. } +//.. +//.. /* An X86RI can only be used in a "read" context (what would it mean +//.. to write or modify a literal?) and so we enumerate its registers +//.. accordingly. */ +//.. static void addRegUsage_X86RI ( HRegUsage* u, X86RI* op ) { +//.. switch (op->tag) { +//.. case Xri_Imm: +//.. return; +//.. case Xri_Reg: +//.. addHRegUse(u, HRmRead, op->Xri.Reg.reg); +//.. return; +//.. default: +//.. vpanic("addRegUsage_X86RI"); +//.. } +//.. } +//.. +//.. static void mapRegs_X86RI ( HRegRemap* m, X86RI* op ) { +//.. switch (op->tag) { +//.. case Xri_Imm: +//.. return; +//.. case Xri_Reg: +//.. op->Xri.Reg.reg = lookupHRegRemap(m, op->Xri.Reg.reg); +//.. return; +//.. default: +//.. vpanic("mapRegs_X86RI"); +//.. } +//.. } +//.. +//.. +//.. /* --------- Operand, which can be reg or memory only. --------- */ +//.. +//.. X86RM* X86RM_Reg ( HReg reg ) { +//.. X86RM* op = LibVEX_Alloc(sizeof(X86RM)); +//.. op->tag = Xrm_Reg; +//.. op->Xrm.Reg.reg = reg; +//.. return op; +//.. } +//.. X86RM* X86RM_Mem ( X86AMode* am ) { +//.. X86RM* op = LibVEX_Alloc(sizeof(X86RM)); +//.. op->tag = Xrm_Mem; +//.. op->Xrm.Mem.am = am; +//.. return op; +//.. } +//.. +//.. void ppX86RM ( X86RM* op ) { +//.. switch (op->tag) { +//.. case Xrm_Mem: +//.. ppX86AMode(op->Xrm.Mem.am); +//.. return; +//.. case Xrm_Reg: +//.. ppHRegX86(op->Xrm.Reg.reg); +//.. return; +//.. default: +//.. vpanic("ppX86RM"); +//.. } +//.. } +//.. +//.. /* Because an X86RM can be both a source or destination operand, we +//.. have to supply a mode -- pertaining to the operand as a whole -- +//.. indicating how it's being used. */ +//.. static void addRegUsage_X86RM ( HRegUsage* u, X86RM* op, HRegMode mode ) { +//.. switch (op->tag) { +//.. case Xrm_Mem: +//.. /* Memory is read, written or modified. So we just want to +//.. know the regs read by the amode. */ +//.. addRegUsage_X86AMode(u, op->Xrm.Mem.am); +//.. return; +//.. case Xrm_Reg: +//.. /* reg is read, written or modified. Add it in the +//.. appropriate way. */ +//.. addHRegUse(u, mode, op->Xrm.Reg.reg); +//.. return; +//.. default: +//.. vpanic("addRegUsage_X86RM"); +//.. } +//.. } +//.. +//.. static void mapRegs_X86RM ( HRegRemap* m, X86RM* op ) +//.. { +//.. switch (op->tag) { +//.. case Xrm_Mem: +//.. mapRegs_X86AMode(m, op->Xrm.Mem.am); +//.. return; +//.. case Xrm_Reg: +//.. op->Xrm.Reg.reg = lookupHRegRemap(m, op->Xrm.Reg.reg); +//.. return; +//.. default: +//.. vpanic("mapRegs_X86RM"); +//.. } +//.. } +//.. +//.. +//.. /* --------- Instructions. --------- */ +//.. +//.. HChar* showX86ScalarSz ( X86ScalarSz sz ) { +//.. switch (sz) { +//.. case Xss_16: return "w"; +//.. case Xss_32: return "l"; +//.. default: vpanic("showX86ScalarSz"); +//.. } +//.. } +//.. +//.. HChar* showX86UnaryOp ( X86UnaryOp op ) { +//.. switch (op) { +//.. case Xun_NOT: return "not"; +//.. case Xun_NEG: return "neg"; +//.. default: vpanic("showX86UnaryOp"); +//.. } +//.. } +//.. +//.. HChar* showX86AluOp ( X86AluOp op ) { +//.. switch (op) { +//.. case Xalu_MOV: return "mov"; +//.. case Xalu_CMP: return "cmp"; +//.. case Xalu_ADD: return "add"; +//.. case Xalu_SUB: return "sub"; +//.. case Xalu_ADC: return "adc"; +//.. case Xalu_SBB: return "sbb"; +//.. case Xalu_AND: return "and"; +//.. case Xalu_OR: return "or"; +//.. case Xalu_XOR: return "xor"; +//.. case Xalu_MUL: return "mul"; +//.. default: vpanic("showX86AluOp"); +//.. } +//.. } +//.. +//.. HChar* showX86ShiftOp ( X86ShiftOp op ) { +//.. switch (op) { +//.. case Xsh_SHL: return "shl"; +//.. case Xsh_SHR: return "shr"; +//.. case Xsh_SAR: return "sar"; +//.. case Xsh_ROL: return "rol"; +//.. case Xsh_ROR: return "ror"; +//.. default: vpanic("showX86ShiftOp"); +//.. } +//.. } +//.. +//.. HChar* showX86FpOp ( X86FpOp op ) { +//.. switch (op) { +//.. case Xfp_ADD: return "add"; +//.. case Xfp_SUB: return "sub"; +//.. case Xfp_MUL: return "mul"; +//.. case Xfp_DIV: return "div"; +//.. case Xfp_SCALE: return "scale"; +//.. case Xfp_ATAN: return "atan"; +//.. case Xfp_YL2X: return "yl2x"; +//.. case Xfp_YL2XP1: return "yl2xp1"; +//.. case Xfp_PREM: return "prem"; +//.. case Xfp_PREM1: return "prem1"; +//.. case Xfp_SQRT: return "sqrt"; +//.. case Xfp_ABS: return "abs"; +//.. case Xfp_NEG: return "chs"; +//.. case Xfp_MOV: return "mov"; +//.. case Xfp_SIN: return "sin"; +//.. case Xfp_COS: return "cos"; +//.. case Xfp_TAN: return "tan"; +//.. case Xfp_ROUND: return "round"; +//.. case Xfp_2XM1: return "2xm1"; +//.. default: vpanic("showX86FpOp"); +//.. } +//.. } +//.. +//.. HChar* showX86SseOp ( X86SseOp op ) { +//.. switch (op) { +//.. case Xsse_MOV: return "mov(?!)"; +//.. case Xsse_ADDF: return "add"; +//.. case Xsse_SUBF: return "sub"; +//.. case Xsse_MULF: return "mul"; +//.. case Xsse_DIVF: return "div"; +//.. case Xsse_MAXF: return "max"; +//.. case Xsse_MINF: return "min"; +//.. case Xsse_CMPEQF: return "cmpFeq"; +//.. case Xsse_CMPLTF: return "cmpFlt"; +//.. case Xsse_CMPLEF: return "cmpFle"; +//.. case Xsse_CMPUNF: return "cmpFun"; +//.. case Xsse_RCPF: return "rcp"; +//.. case Xsse_RSQRTF: return "rsqrt"; +//.. case Xsse_SQRTF: return "sqrt"; +//.. case Xsse_AND: return "and"; +//.. case Xsse_OR: return "or"; +//.. case Xsse_XOR: return "xor"; +//.. case Xsse_ANDN: return "andn"; +//.. case Xsse_ADD8: return "paddb"; +//.. case Xsse_ADD16: return "paddw"; +//.. case Xsse_ADD32: return "paddd"; +//.. case Xsse_ADD64: return "paddq"; +//.. case Xsse_QADD8U: return "paddusb"; +//.. case Xsse_QADD16U: return "paddusw"; +//.. case Xsse_QADD8S: return "paddsb"; +//.. case Xsse_QADD16S: return "paddsw"; +//.. case Xsse_SUB8: return "psubb"; +//.. case Xsse_SUB16: return "psubw"; +//.. case Xsse_SUB32: return "psubd"; +//.. case Xsse_SUB64: return "psubq"; +//.. case Xsse_QSUB8U: return "psubusb"; +//.. case Xsse_QSUB16U: return "psubusw"; +//.. case Xsse_QSUB8S: return "psubsb"; +//.. case Xsse_QSUB16S: return "psubsw"; +//.. case Xsse_MUL16: return "pmullw"; +//.. case Xsse_MULHI16U: return "pmulhuw"; +//.. case Xsse_MULHI16S: return "pmulhw"; +//.. case Xsse_AVG8U: return "pavgb"; +//.. case Xsse_AVG16U: return "pavgw"; +//.. case Xsse_MAX16S: return "pmaxw"; +//.. case Xsse_MAX8U: return "pmaxub"; +//.. case Xsse_MIN16S: return "pminw"; +//.. case Xsse_MIN8U: return "pminub"; +//.. case Xsse_CMPEQ8: return "pcmpeqb"; +//.. case Xsse_CMPEQ16: return "pcmpeqw"; +//.. case Xsse_CMPEQ32: return "pcmpeqd"; +//.. case Xsse_CMPGT8S: return "pcmpgtb"; +//.. case Xsse_CMPGT16S: return "pcmpgtw"; +//.. case Xsse_CMPGT32S: return "pcmpgtd"; +//.. case Xsse_SHL16: return "psllw"; +//.. case Xsse_SHL32: return "pslld"; +//.. case Xsse_SHL64: return "psllq"; +//.. case Xsse_SHR16: return "psrlw"; +//.. case Xsse_SHR32: return "psrld"; +//.. case Xsse_SHR64: return "psrlq"; +//.. case Xsse_SAR16: return "psraw"; +//.. case Xsse_SAR32: return "psrad"; +//.. case Xsse_PACKSSD: return "packssdw"; +//.. case Xsse_PACKSSW: return "packsswb"; +//.. case Xsse_PACKUSW: return "packuswb"; +//.. case Xsse_UNPCKHB: return "punpckhb"; +//.. case Xsse_UNPCKHW: return "punpckhw"; +//.. case Xsse_UNPCKHD: return "punpckhd"; +//.. case Xsse_UNPCKHQ: return "punpckhq"; +//.. case Xsse_UNPCKLB: return "punpcklb"; +//.. case Xsse_UNPCKLW: return "punpcklw"; +//.. case Xsse_UNPCKLD: return "punpckld"; +//.. case Xsse_UNPCKLQ: return "punpcklq"; +//.. default: vpanic("showX86SseOp"); +//.. } +//.. } +//.. +//.. X86Instr* X86Instr_Alu32R ( X86AluOp op, X86RMI* src, HReg dst ) { +//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); +//.. i->tag = Xin_Alu32R; +//.. i->Xin.Alu32R.op = op; +//.. i->Xin.Alu32R.src = src; +//.. i->Xin.Alu32R.dst = dst; +//.. return i; +//.. } +//.. X86Instr* X86Instr_Alu32M ( X86AluOp op, X86RI* src, X86AMode* dst ) { +//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); +//.. i->tag = Xin_Alu32M; +//.. i->Xin.Alu32M.op = op; +//.. i->Xin.Alu32M.src = src; +//.. i->Xin.Alu32M.dst = dst; +//.. vassert(op != Xalu_MUL); +//.. return i; +//.. } +//.. X86Instr* X86Instr_Sh32 ( X86ShiftOp op, UInt src, X86RM* dst ) { +//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); +//.. i->tag = Xin_Sh32; +//.. i->Xin.Sh32.op = op; +//.. i->Xin.Sh32.src = src; +//.. i->Xin.Sh32.dst = dst; +//.. return i; +//.. } +//.. X86Instr* X86Instr_Test32 ( X86RI* src, X86RM* dst ) { +//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); +//.. i->tag = Xin_Test32; +//.. i->Xin.Test32.src = src; +//.. i->Xin.Test32.dst = dst; +//.. return i; +//.. } +//.. X86Instr* X86Instr_Unary32 ( X86UnaryOp op, X86RM* dst ) { +//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); +//.. i->tag = Xin_Unary32; +//.. i->Xin.Unary32.op = op; +//.. i->Xin.Unary32.dst = dst; +//.. return i; +//.. } +//.. X86Instr* X86Instr_MulL ( Bool syned, X86ScalarSz ssz , X86RM* src ) { +//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); +//.. i->tag = Xin_MulL; +//.. i->Xin.MulL.syned = syned; +//.. i->Xin.MulL.ssz = ssz; +//.. i->Xin.MulL.src = src; +//.. return i; +//.. } +//.. X86Instr* X86Instr_Div ( Bool syned, X86ScalarSz ssz, X86RM* src ) { +//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); +//.. i->tag = Xin_Div; +//.. i->Xin.Div.syned = syned; +//.. i->Xin.Div.ssz = ssz; +//.. i->Xin.Div.src = src; +//.. return i; +//.. } +//.. X86Instr* X86Instr_Sh3232 ( X86ShiftOp op, UInt amt, HReg src, HReg dst ) { +//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); +//.. i->tag = Xin_Sh3232; +//.. i->Xin.Sh3232.op = op; +//.. i->Xin.Sh3232.amt = amt; +//.. i->Xin.Sh3232.src = src; +//.. i->Xin.Sh3232.dst = dst; +//.. vassert(op == Xsh_SHL || op == Xsh_SHR); +//.. return i; +//.. } +//.. X86Instr* X86Instr_Push( X86RMI* src ) { +//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); +//.. i->tag = Xin_Push; +//.. i->Xin.Push.src = src; +//.. return i; +//.. } +//.. X86Instr* X86Instr_Call ( X86CondCode cond, Addr32 target, Int regparms ) { +//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); +//.. i->tag = Xin_Call; +//.. i->Xin.Call.cond = cond; +//.. i->Xin.Call.target = target; +//.. i->Xin.Call.regparms = regparms; +//.. vassert(regparms >= 0 && regparms <= 3); +//.. return i; +//.. } +//.. X86Instr* X86Instr_Goto ( IRJumpKind jk, X86CondCode cond, X86RI* dst ) { +//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); +//.. i->tag = Xin_Goto; +//.. i->Xin.Goto.cond = cond; +//.. i->Xin.Goto.dst = dst; +//.. i->Xin.Goto.jk = jk; +//.. return i; +//.. } +//.. X86Instr* X86Instr_CMov32 ( X86CondCode cond, X86RM* src, HReg dst ) { +//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); +//.. i->tag = Xin_CMov32; +//.. i->Xin.CMov32.cond = cond; +//.. i->Xin.CMov32.src = src; +//.. i->Xin.CMov32.dst = dst; +//.. vassert(cond != Xcc_ALWAYS); +//.. return i; +//.. } +//.. X86Instr* X86Instr_LoadEX ( UChar szSmall, Bool syned, +//.. X86AMode* src, HReg dst ) { +//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); +//.. i->tag = Xin_LoadEX; +//.. i->Xin.LoadEX.szSmall = szSmall; +//.. i->Xin.LoadEX.syned = syned; +//.. i->Xin.LoadEX.src = src; +//.. i->Xin.LoadEX.dst = dst; +//.. vassert(szSmall == 1 || szSmall == 2); +//.. return i; +//.. } +//.. X86Instr* X86Instr_Store ( UChar sz, HReg src, X86AMode* dst ) { +//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); +//.. i->tag = Xin_Store; +//.. i->Xin.Store.sz = sz; +//.. i->Xin.Store.src = src; +//.. i->Xin.Store.dst = dst; +//.. vassert(sz == 1 || sz == 2); +//.. return i; +//.. } +//.. X86Instr* X86Instr_Set32 ( X86CondCode cond, HReg dst ) { +//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); +//.. i->tag = Xin_Set32; +//.. i->Xin.Set32.cond = cond; +//.. i->Xin.Set32.dst = dst; +//.. return i; +//.. } +//.. X86Instr* X86Instr_Bsfr32 ( Bool isFwds, HReg src, HReg dst ) { +//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); +//.. i->tag = Xin_Bsfr32; +//.. i->Xin.Bsfr32.isFwds = isFwds; +//.. i->Xin.Bsfr32.src = src; +//.. i->Xin.Bsfr32.dst = dst; +//.. return i; +//.. } +//.. X86Instr* X86Instr_MFence ( VexSubArch subarch ) +//.. { +//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); +//.. i->tag = Xin_MFence; +//.. i->Xin.MFence.subarch = subarch; +//.. vassert(subarch == VexSubArchX86_sse0 +//.. || subarch == VexSubArchX86_sse1 +//.. || subarch == VexSubArchX86_sse2); +//.. return i; +//.. } +//.. +//.. X86Instr* X86Instr_FpUnary ( X86FpOp op, HReg src, HReg dst ) { +//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); +//.. i->tag = Xin_FpUnary; +//.. i->Xin.FpUnary.op = op; +//.. i->Xin.FpUnary.src = src; +//.. i->Xin.FpUnary.dst = dst; +//.. return i; +//.. } +//.. X86Instr* X86Instr_FpBinary ( X86FpOp op, HReg srcL, HReg srcR, HReg dst ) { +//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); +//.. i->tag = Xin_FpBinary; +//.. i->Xin.FpBinary.op = op; +//.. i->Xin.FpBinary.srcL = srcL; +//.. i->Xin.FpBinary.srcR = srcR; +//.. i->Xin.FpBinary.dst = dst; +//.. return i; +//.. } +//.. X86Instr* X86Instr_FpLdSt ( Bool isLoad, UChar sz, HReg reg, X86AMode* addr ) { +//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); +//.. i->tag = Xin_FpLdSt; +//.. i->Xin.FpLdSt.isLoad = isLoad; +//.. i->Xin.FpLdSt.sz = sz; +//.. i->Xin.FpLdSt.reg = reg; +//.. i->Xin.FpLdSt.addr = addr; +//.. vassert(sz == 4 || sz == 8); +//.. return i; +//.. } +//.. X86Instr* X86Instr_FpLdStI ( Bool isLoad, UChar sz, +//.. HReg reg, X86AMode* addr ) { +//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); +//.. i->tag = Xin_FpLdStI; +//.. i->Xin.FpLdStI.isLoad = isLoad; +//.. i->Xin.FpLdStI.sz = sz; +//.. i->Xin.FpLdStI.reg = reg; +//.. i->Xin.FpLdStI.addr = addr; +//.. vassert(sz == 2 || sz == 4 || sz == 8); +//.. return i; +//.. } +//.. X86Instr* X86Instr_Fp64to32 ( HReg src, HReg dst ) { +//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); +//.. i->tag = Xin_Fp64to32; +//.. i->Xin.Fp64to32.src = src; +//.. i->Xin.Fp64to32.dst = dst; +//.. return i; +//.. } +//.. X86Instr* X86Instr_FpCMov ( X86CondCode cond, HReg src, HReg dst ) { +//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); +//.. i->tag = Xin_FpCMov; +//.. i->Xin.FpCMov.cond = cond; +//.. i->Xin.FpCMov.src = src; +//.. i->Xin.FpCMov.dst = dst; +//.. vassert(cond != Xcc_ALWAYS); +//.. return i; +//.. } +//.. X86Instr* X86Instr_FpLdStCW ( Bool isLoad, X86AMode* addr ) { +//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); +//.. i->tag = Xin_FpLdStCW; +//.. i->Xin.FpLdStCW.isLoad = isLoad; +//.. i->Xin.FpLdStCW.addr = addr; +//.. return i; +//.. } +//.. X86Instr* X86Instr_FpStSW_AX ( void ) { +//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); +//.. i->tag = Xin_FpStSW_AX; +//.. return i; +//.. } +//.. X86Instr* X86Instr_FpCmp ( HReg srcL, HReg srcR, HReg dst ) { +//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); +//.. i->tag = Xin_FpCmp; +//.. i->Xin.FpCmp.srcL = srcL; +//.. i->Xin.FpCmp.srcR = srcR; +//.. i->Xin.FpCmp.dst = dst; +//.. return i; +//.. } +//.. +//.. X86Instr* X86Instr_SseConst ( UShort con, HReg dst ) { +//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); +//.. i->tag = Xin_SseConst; +//.. i->Xin.SseConst.con = con; +//.. i->Xin.SseConst.dst = dst; +//.. vassert(hregClass(dst) == HRcVec128); +//.. return i; +//.. } +//.. X86Instr* X86Instr_SseLdSt ( Bool isLoad, HReg reg, X86AMode* addr ) { +//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); +//.. i->tag = Xin_SseLdSt; +//.. i->Xin.SseLdSt.isLoad = isLoad; +//.. i->Xin.SseLdSt.reg = reg; +//.. i->Xin.SseLdSt.addr = addr; +//.. return i; +//.. } +//.. X86Instr* X86Instr_SseLdzLO ( Int sz, HReg reg, X86AMode* addr ) +//.. { +//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); +//.. i->tag = Xin_SseLdzLO; +//.. i->Xin.SseLdzLO.sz = sz; +//.. i->Xin.SseLdzLO.reg = reg; +//.. i->Xin.SseLdzLO.addr = addr; +//.. vassert(sz == 4 || sz == 8); +//.. return i; +//.. } +//.. X86Instr* X86Instr_Sse32Fx4 ( X86SseOp op, HReg src, HReg dst ) { +//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); +//.. i->tag = Xin_Sse32Fx4; +//.. i->Xin.Sse32Fx4.op = op; +//.. i->Xin.Sse32Fx4.src = src; +//.. i->Xin.Sse32Fx4.dst = dst; +//.. vassert(op != Xsse_MOV); +//.. return i; +//.. } +//.. X86Instr* X86Instr_Sse32FLo ( X86SseOp op, HReg src, HReg dst ) { +//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); +//.. i->tag = Xin_Sse32FLo; +//.. i->Xin.Sse32FLo.op = op; +//.. i->Xin.Sse32FLo.src = src; +//.. i->Xin.Sse32FLo.dst = dst; +//.. vassert(op != Xsse_MOV); +//.. return i; +//.. } +//.. X86Instr* X86Instr_Sse64Fx2 ( X86SseOp op, HReg src, HReg dst ) { +//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); +//.. i->tag = Xin_Sse64Fx2; +//.. i->Xin.Sse64Fx2.op = op; +//.. i->Xin.Sse64Fx2.src = src; +//.. i->Xin.Sse64Fx2.dst = dst; +//.. vassert(op != Xsse_MOV); +//.. return i; +//.. } +//.. X86Instr* X86Instr_Sse64FLo ( X86SseOp op, HReg src, HReg dst ) { +//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); +//.. i->tag = Xin_Sse64FLo; +//.. i->Xin.Sse64FLo.op = op; +//.. i->Xin.Sse64FLo.src = src; +//.. i->Xin.Sse64FLo.dst = dst; +//.. vassert(op != Xsse_MOV); +//.. return i; +//.. } +//.. X86Instr* X86Instr_SseReRg ( X86SseOp op, HReg re, HReg rg ) { +//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); +//.. i->tag = Xin_SseReRg; +//.. i->Xin.SseReRg.op = op; +//.. i->Xin.SseReRg.src = re; +//.. i->Xin.SseReRg.dst = rg; +//.. return i; +//.. } +//.. X86Instr* X86Instr_SseCMov ( X86CondCode cond, HReg src, HReg dst ) { +//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); +//.. i->tag = Xin_SseCMov; +//.. i->Xin.SseCMov.cond = cond; +//.. i->Xin.SseCMov.src = src; +//.. i->Xin.SseCMov.dst = dst; +//.. vassert(cond != Xcc_ALWAYS); +//.. return i; +//.. } +//.. X86Instr* X86Instr_SseShuf ( Int order, HReg src, HReg dst ) { +//.. X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); +//.. i->tag = Xin_SseShuf; +//.. i->Xin.SseShuf.order = order; +//.. i->Xin.SseShuf.src = src; +//.. i->Xin.SseShuf.dst = dst; +//.. vassert(order >= 0 && order <= 0xFF); +//.. return i; +//.. } + +void ppPPC32Instr ( PPC32Instr* i ) +{ + switch (i->tag) { +//.. case Xin_Alu32R: +//.. vex_printf("%sl ", showX86AluOp(i->Xin.Alu32R.op)); +//.. ppX86RMI(i->Xin.Alu32R.src); +//.. vex_printf(","); +//.. ppHRegX86(i->Xin.Alu32R.dst); +//.. return; +//.. case Xin_Alu32M: +//.. vex_printf("%sl ", showX86AluOp(i->Xin.Alu32M.op)); +//.. ppX86RI(i->Xin.Alu32M.src); +//.. vex_printf(","); +//.. ppX86AMode(i->Xin.Alu32M.dst); +//.. return; +//.. case Xin_Sh32: +//.. vex_printf("%sl ", showX86ShiftOp(i->Xin.Sh32.op)); +//.. if (i->Xin.Sh32.src == 0) +//.. vex_printf("%%cl,"); +//.. else +//.. vex_printf("$%d,", i->Xin.Sh32.src); +//.. ppX86RM(i->Xin.Sh32.dst); +//.. return; +//.. case Xin_Test32: +//.. vex_printf("testl "); +//.. ppX86RI(i->Xin.Test32.src); +//.. vex_printf(","); +//.. ppX86RM(i->Xin.Test32.dst); +//.. return; +//.. case Xin_Unary32: +//.. vex_printf("%sl ", showX86UnaryOp(i->Xin.Unary32.op)); +//.. ppX86RM(i->Xin.Unary32.dst); +//.. return; +//.. case Xin_MulL: +//.. vex_printf("%cmul%s ", +//.. i->Xin.MulL.syned ? 's' : 'u', +//.. showX86ScalarSz(i->Xin.MulL.ssz)); +//.. ppX86RM(i->Xin.MulL.src); +//.. return; +//.. case Xin_Div: +//.. vex_printf("%cdiv%s ", +//.. i->Xin.Div.syned ? 's' : 'u', +//.. showX86ScalarSz(i->Xin.Div.ssz)); +//.. ppX86RM(i->Xin.Div.src); +//.. return; +//.. case Xin_Sh3232: +//.. vex_printf("%sdl ", showX86ShiftOp(i->Xin.Sh3232.op)); +//.. if (i->Xin.Sh3232.amt == 0) +//.. vex_printf(" %%cl,"); +//.. else +//.. vex_printf(" $%d,", i->Xin.Sh3232.amt); +//.. ppHRegX86(i->Xin.Sh3232.src); +//.. vex_printf(","); +//.. ppHRegX86(i->Xin.Sh3232.dst); +//.. return; +//.. case Xin_Push: +//.. vex_printf("pushl "); +//.. ppX86RMI(i->Xin.Push.src); +//.. return; +//.. case Xin_Call: +//.. vex_printf("call%s[%d] ", +//.. i->Xin.Call.cond==Xcc_ALWAYS +//.. ? "" : showX86CondCode(i->Xin.Call.cond), +//.. i->Xin.Call.regparms); +//.. vex_printf("0x%x", i->Xin.Call.target); +//.. break; +//.. case Xin_Goto: +//.. if (i->Xin.Goto.cond != Xcc_ALWAYS) { +//.. vex_printf("if (%%eflags.%s) { ", +//.. showX86CondCode(i->Xin.Goto.cond)); +//.. } +//.. if (i->Xin.Goto.jk != Ijk_Boring) { +//.. vex_printf("movl $"); +//.. ppIRJumpKind(i->Xin.Goto.jk); +//.. vex_printf(",%%ebp ; "); +//.. } +//.. vex_printf("movl "); +//.. ppX86RI(i->Xin.Goto.dst); +//.. vex_printf(",%%eax ; ret"); +//.. if (i->Xin.Goto.cond != Xcc_ALWAYS) { +//.. vex_printf(" }"); +//.. } +//.. return; +//.. case Xin_CMov32: +//.. vex_printf("cmov%s ", showX86CondCode(i->Xin.CMov32.cond)); +//.. ppX86RM(i->Xin.CMov32.src); +//.. vex_printf(","); +//.. ppHRegX86(i->Xin.CMov32.dst); +//.. return; +//.. case Xin_LoadEX: +//.. vex_printf("mov%c%cl ", +//.. i->Xin.LoadEX.syned ? 's' : 'z', +//.. i->Xin.LoadEX.szSmall==1 ? 'b' : 'w'); +//.. ppX86AMode(i->Xin.LoadEX.src); +//.. vex_printf(","); +//.. ppHRegX86(i->Xin.LoadEX.dst); +//.. return; +//.. case Xin_Store: +//.. vex_printf("mov%c ", i->Xin.Store.sz==1 ? 'b' : 'w'); +//.. ppHRegX86(i->Xin.Store.src); +//.. vex_printf(","); +//.. ppX86AMode(i->Xin.Store.dst); +//.. return; +//.. case Xin_Set32: +//.. vex_printf("setl%s ", showX86CondCode(i->Xin.Set32.cond)); +//.. ppHRegX86(i->Xin.Set32.dst); +//.. return; +//.. case Xin_Bsfr32: +//.. vex_printf("bs%cl ", i->Xin.Bsfr32.isFwds ? 'f' : 'r'); +//.. ppHRegX86(i->Xin.Bsfr32.src); +//.. vex_printf(","); +//.. ppHRegX86(i->Xin.Bsfr32.dst); +//.. return; +//.. case Xin_MFence: +//.. vex_printf("mfence(%s)", +//.. LibVEX_ppVexSubArch(i->Xin.MFence.subarch)); +//.. return; +//.. case Xin_FpUnary: +//.. vex_printf("g%sD ", showX86FpOp(i->Xin.FpUnary.op)); +//.. ppHRegX86(i->Xin.FpUnary.src); +//.. vex_printf(","); +//.. ppHRegX86(i->Xin.FpUnary.dst); +//.. break; +//.. case Xin_FpBinary: +//.. vex_printf("g%sD ", showX86FpOp(i->Xin.FpBinary.op)); +//.. ppHRegX86(i->Xin.FpBinary.srcL); +//.. vex_printf(","); +//.. ppHRegX86(i->Xin.FpBinary.srcR); +//.. vex_printf(","); +//.. ppHRegX86(i->Xin.FpBinary.dst); +//.. break; +//.. case Xin_FpLdSt: +//.. if (i->Xin.FpLdSt.isLoad) { +//.. vex_printf("gld%c " , i->Xin.FpLdSt.sz==8 ? 'D' : 'F'); +//.. ppX86AMode(i->Xin.FpLdSt.addr); +//.. vex_printf(", "); +//.. ppHRegX86(i->Xin.FpLdSt.reg); +//.. } else { +//.. vex_printf("gst%c " , i->Xin.FpLdSt.sz==8 ? 'D' : 'F'); +//.. ppHRegX86(i->Xin.FpLdSt.reg); +//.. vex_printf(", "); +//.. ppX86AMode(i->Xin.FpLdSt.addr); +//.. } +//.. return; +//.. case Xin_FpLdStI: +//.. if (i->Xin.FpLdStI.isLoad) { +//.. vex_printf("gild%s ", i->Xin.FpLdStI.sz==8 ? "ll" : +//.. i->Xin.FpLdStI.sz==4 ? "l" : "w"); +//.. ppX86AMode(i->Xin.FpLdStI.addr); +//.. vex_printf(", "); +//.. ppHRegX86(i->Xin.FpLdStI.reg); +//.. } else { +//.. vex_printf("gist%s ", i->Xin.FpLdStI.sz==8 ? "ll" : +//.. i->Xin.FpLdStI.sz==4 ? "l" : "w"); +//.. ppHRegX86(i->Xin.FpLdStI.reg); +//.. vex_printf(", "); +//.. ppX86AMode(i->Xin.FpLdStI.addr); +//.. } +//.. return; +//.. case Xin_Fp64to32: +//.. vex_printf("gdtof "); +//.. ppHRegX86(i->Xin.Fp64to32.src); +//.. vex_printf(","); +//.. ppHRegX86(i->Xin.Fp64to32.dst); +//.. return; +//.. case Xin_FpCMov: +//.. vex_printf("gcmov%s ", showX86CondCode(i->Xin.FpCMov.cond)); +//.. ppHRegX86(i->Xin.FpCMov.src); +//.. vex_printf(","); +//.. ppHRegX86(i->Xin.FpCMov.dst); +//.. return; +//.. case Xin_FpLdStCW: +//.. vex_printf(i->Xin.FpLdStCW.isLoad ? "fldcw " : "fstcw "); +//.. ppX86AMode(i->Xin.FpLdStCW.addr); +//.. return; +//.. case Xin_FpStSW_AX: +//.. vex_printf("fstsw %%ax"); +//.. return; +//.. case Xin_FpCmp: +//.. vex_printf("gcmp "); +//.. ppHRegX86(i->Xin.FpCmp.srcL); +//.. vex_printf(","); +//.. ppHRegX86(i->Xin.FpCmp.srcR); +//.. vex_printf(","); +//.. ppHRegX86(i->Xin.FpCmp.dst); +//.. break; +//.. case Xin_SseConst: +//.. vex_printf("const $0x%04x,", (Int)i->Xin.SseConst.con); +//.. ppHRegX86(i->Xin.SseConst.dst); +//.. break; +//.. case Xin_SseLdSt: +//.. vex_printf("movups "); +//.. if (i->Xin.SseLdSt.isLoad) { +//.. ppX86AMode(i->Xin.SseLdSt.addr); +//.. vex_printf(","); +//.. ppHRegX86(i->Xin.SseLdSt.reg); +//.. } else { +//.. ppHRegX86(i->Xin.SseLdSt.reg); +//.. vex_printf(","); +//.. ppX86AMode(i->Xin.SseLdSt.addr); +//.. } +//.. return; +//.. case Xin_SseLdzLO: +//.. vex_printf("movs%s ", i->Xin.SseLdzLO.sz==4 ? "s" : "d"); +//.. ppX86AMode(i->Xin.SseLdzLO.addr); +//.. vex_printf(","); +//.. ppHRegX86(i->Xin.SseLdzLO.reg); +//.. return; +//.. case Xin_Sse32Fx4: +//.. vex_printf("%sps ", showX86SseOp(i->Xin.Sse32Fx4.op)); +//.. ppHRegX86(i->Xin.Sse32Fx4.src); +//.. vex_printf(","); +//.. ppHRegX86(i->Xin.Sse32Fx4.dst); +//.. return; +//.. case Xin_Sse32FLo: +//.. vex_printf("%sss ", showX86SseOp(i->Xin.Sse32FLo.op)); +//.. ppHRegX86(i->Xin.Sse32FLo.src); +//.. vex_printf(","); +//.. ppHRegX86(i->Xin.Sse32FLo.dst); +//.. return; +//.. case Xin_Sse64Fx2: +//.. vex_printf("%spd ", showX86SseOp(i->Xin.Sse64Fx2.op)); +//.. ppHRegX86(i->Xin.Sse64Fx2.src); +//.. vex_printf(","); +//.. ppHRegX86(i->Xin.Sse64Fx2.dst); +//.. return; +//.. case Xin_Sse64FLo: +//.. vex_printf("%ssd ", showX86SseOp(i->Xin.Sse64FLo.op)); +//.. ppHRegX86(i->Xin.Sse64FLo.src); +//.. vex_printf(","); +//.. ppHRegX86(i->Xin.Sse64FLo.dst); +//.. return; +//.. case Xin_SseReRg: +//.. vex_printf("%s ", showX86SseOp(i->Xin.SseReRg.op)); +//.. ppHRegX86(i->Xin.SseReRg.src); +//.. vex_printf(","); +//.. ppHRegX86(i->Xin.SseReRg.dst); +//.. return; +//.. case Xin_SseCMov: +//.. vex_printf("cmov%s ", showX86CondCode(i->Xin.SseCMov.cond)); +//.. ppHRegX86(i->Xin.SseCMov.src); +//.. vex_printf(","); +//.. ppHRegX86(i->Xin.SseCMov.dst); +//.. return; +//.. case Xin_SseShuf: +//.. vex_printf("pshufd $0x%x,", i->Xin.SseShuf.order); +//.. ppHRegX86(i->Xin.SseShuf.src); +//.. vex_printf(","); +//.. ppHRegX86(i->Xin.SseShuf.dst); +//.. return; + + default: + vpanic("ppPPC32Instr"); + } +} + +/* --------- Helpers for register allocation. --------- */ + +void getRegUsage_PPC32Instr ( HRegUsage* u, PPC32Instr* i ) +{ +// Bool unary; + initHRegUsage(u); + switch (i->tag) { +//.. case Xin_Alu32R: +//.. addRegUsage_X86RMI(u, i->Xin.Alu32R.src); +//.. if (i->Xin.Alu32R.op == Xalu_MOV) { +//.. addHRegUse(u, HRmWrite, i->Xin.Alu32R.dst); +//.. return; +//.. } +//.. if (i->Xin.Alu32R.op == Xalu_CMP) { +//.. addHRegUse(u, HRmRead, i->Xin.Alu32R.dst); +//.. return; +//.. } +//.. addHRegUse(u, HRmModify, i->Xin.Alu32R.dst); +//.. return; +//.. case Xin_Alu32M: +//.. addRegUsage_X86RI(u, i->Xin.Alu32M.src); +//.. addRegUsage_X86AMode(u, i->Xin.Alu32M.dst); +//.. return; +//.. case Xin_Sh32: +//.. addRegUsage_X86RM(u, i->Xin.Sh32.dst, HRmModify); +//.. if (i->Xin.Sh32.src == 0) +//.. addHRegUse(u, HRmRead, hregX86_ECX()); +//.. return; +//.. case Xin_Test32: +//.. addRegUsage_X86RI(u, i->Xin.Test32.src); +//.. addRegUsage_X86RM(u, i->Xin.Test32.dst, HRmRead); +//.. return; +//.. case Xin_Unary32: +//.. addRegUsage_X86RM(u, i->Xin.Unary32.dst, HRmModify); +//.. return; +//.. case Xin_MulL: +//.. addRegUsage_X86RM(u, i->Xin.MulL.src, HRmRead); +//.. addHRegUse(u, HRmModify, hregX86_EAX()); +//.. addHRegUse(u, HRmWrite, hregX86_EDX()); +//.. return; +//.. case Xin_Div: +//.. addRegUsage_X86RM(u, i->Xin.Div.src, HRmRead); +//.. addHRegUse(u, HRmModify, hregX86_EAX()); +//.. addHRegUse(u, HRmModify, hregX86_EDX()); +//.. return; +//.. case Xin_Sh3232: +//.. addHRegUse(u, HRmRead, i->Xin.Sh3232.src); +//.. addHRegUse(u, HRmModify, i->Xin.Sh3232.dst); +//.. if (i->Xin.Sh3232.amt == 0) +//.. addHRegUse(u, HRmRead, hregX86_ECX()); +//.. return; +//.. case Xin_Push: +//.. addRegUsage_X86RMI(u, i->Xin.Push.src); +//.. addHRegUse(u, HRmModify, hregX86_ESP()); +//.. return; +//.. case Xin_Call: +//.. /* This is a bit subtle. */ +//.. /* First off, claim it trashes all the callee-saved regs */ +//.. /* which I believe to be %eax,%ecx,%edx. */ +//.. addHRegUse(u, HRmWrite, hregX86_EAX()); +//.. addHRegUse(u, HRmWrite, hregX86_ECX()); +//.. addHRegUse(u, HRmWrite, hregX86_EDX()); +//.. /* Now we have to state any parameter-carrying registers +//.. which might be read. This depends on the regparmness. */ +//.. switch (i->Xin.Call.regparms) { +//.. case 3: addHRegUse(u, HRmRead, hregX86_ECX()); /*fallthru*/ +//.. case 2: addHRegUse(u, HRmRead, hregX86_EDX()); /*fallthru*/ +//.. case 1: addHRegUse(u, HRmRead, hregX86_EAX()); break; +//.. case 0: break; +//.. default: vpanic("getRegUsage_X86Instr:Call:regparms"); +//.. } +//.. /* Finally, there is the issue that the insn trashes a +//.. register because the literal target address has to be +//.. loaded into a register. Fortunately, for the 0/1/2 +//.. regparm case, we can use EAX, EDX and ECX respectively, so +//.. this does not cause any further damage. For the 3-regparm +//.. case, we'll have to choose another register arbitrarily -- +//.. since A, D and C are used for parameters -- and so we might +//.. as well choose EDI. */ +//.. if (i->Xin.Call.regparms == 3) +//.. addHRegUse(u, HRmWrite, hregX86_EDI()); +//.. /* Upshot of this is that the assembler really must observe +//.. the here-stated convention of which register to use as an +//.. address temporary, depending on the regparmness: 0==EAX, +//.. 1==EDX, 2==ECX, 3==EDI. */ +//.. return; +//.. case Xin_Goto: +//.. addRegUsage_X86RI(u, i->Xin.Goto.dst); +//.. addHRegUse(u, HRmWrite, hregX86_EAX()); +//.. if (i->Xin.Goto.jk != Ijk_Boring) +//.. addHRegUse(u, HRmWrite, hregX86_EBP()); +//.. return; +//.. case Xin_CMov32: +//.. addRegUsage_X86RM(u, i->Xin.CMov32.src, HRmRead); +//.. addHRegUse(u, HRmModify, i->Xin.CMov32.dst); +//.. return; +//.. case Xin_LoadEX: +//.. addRegUsage_X86AMode(u, i->Xin.LoadEX.src); +//.. addHRegUse(u, HRmWrite, i->Xin.LoadEX.dst); +//.. return; +//.. case Xin_Store: +//.. addHRegUse(u, HRmRead, i->Xin.Store.src); +//.. addRegUsage_X86AMode(u, i->Xin.Store.dst); +//.. return; +//.. case Xin_Set32: +//.. addHRegUse(u, HRmWrite, i->Xin.Set32.dst); +//.. return; +//.. case Xin_Bsfr32: +//.. addHRegUse(u, HRmRead, i->Xin.Bsfr32.src); +//.. addHRegUse(u, HRmWrite, i->Xin.Bsfr32.dst); +//.. return; +//.. case Xin_MFence: +//.. return; +//.. case Xin_FpUnary: +//.. addHRegUse(u, HRmRead, i->Xin.FpUnary.src); +//.. addHRegUse(u, HRmWrite, i->Xin.FpUnary.dst); +//.. return; +//.. case Xin_FpBinary: +//.. addHRegUse(u, HRmRead, i->Xin.FpBinary.srcL); +//.. addHRegUse(u, HRmRead, i->Xin.FpBinary.srcR); +//.. addHRegUse(u, HRmWrite, i->Xin.FpBinary.dst); +//.. return; +//.. case Xin_FpLdSt: +//.. addRegUsage_X86AMode(u, i->Xin.FpLdSt.addr); +//.. addHRegUse(u, i->Xin.FpLdSt.isLoad ? HRmWrite : HRmRead, +//.. i->Xin.FpLdSt.reg); +//.. return; +//.. case Xin_FpLdStI: +//.. addRegUsage_X86AMode(u, i->Xin.FpLdStI.addr); +//.. addHRegUse(u, i->Xin.FpLdStI.isLoad ? HRmWrite : HRmRead, +//.. i->Xin.FpLdStI.reg); +//.. return; +//.. case Xin_Fp64to32: +//.. addHRegUse(u, HRmRead, i->Xin.Fp64to32.src); +//.. addHRegUse(u, HRmWrite, i->Xin.Fp64to32.dst); +//.. return; +//.. case Xin_FpCMov: +//.. addHRegUse(u, HRmRead, i->Xin.FpCMov.src); +//.. addHRegUse(u, HRmModify, i->Xin.FpCMov.dst); +//.. return; +//.. case Xin_FpLdStCW: +//.. addRegUsage_X86AMode(u, i->Xin.FpLdStCW.addr); +//.. return; +//.. case Xin_FpStSW_AX: +//.. addHRegUse(u, HRmWrite, hregX86_EAX()); +//.. return; +//.. case Xin_FpCmp: +//.. addHRegUse(u, HRmRead, i->Xin.FpCmp.srcL); +//.. addHRegUse(u, HRmRead, i->Xin.FpCmp.srcR); +//.. addHRegUse(u, HRmWrite, i->Xin.FpCmp.dst); +//.. addHRegUse(u, HRmWrite, hregX86_EAX()); +//.. return; +//.. case Xin_SseLdSt: +//.. addRegUsage_X86AMode(u, i->Xin.SseLdSt.addr); +//.. addHRegUse(u, i->Xin.SseLdSt.isLoad ? HRmWrite : HRmRead, +//.. i->Xin.SseLdSt.reg); +//.. return; +//.. case Xin_SseLdzLO: +//.. addRegUsage_X86AMode(u, i->Xin.SseLdzLO.addr); +//.. addHRegUse(u, HRmWrite, i->Xin.SseLdzLO.reg); +//.. return; +//.. case Xin_SseConst: +//.. addHRegUse(u, HRmWrite, i->Xin.SseConst.dst); +//.. return; +//.. case Xin_Sse32Fx4: +//.. vassert(i->Xin.Sse32Fx4.op != Xsse_MOV); +//.. unary = i->Xin.Sse32Fx4.op == Xsse_RCPF +//.. || i->Xin.Sse32Fx4.op == Xsse_RSQRTF +//.. || i->Xin.Sse32Fx4.op == Xsse_SQRTF; +//.. addHRegUse(u, HRmRead, i->Xin.Sse32Fx4.src); +//.. addHRegUse(u, unary ? HRmWrite : HRmModify, +//.. i->Xin.Sse32Fx4.dst); +//.. return; +//.. case Xin_Sse32FLo: +//.. vassert(i->Xin.Sse32FLo.op != Xsse_MOV); +//.. unary = i->Xin.Sse32FLo.op == Xsse_RCPF +//.. || i->Xin.Sse32FLo.op == Xsse_RSQRTF +//.. || i->Xin.Sse32FLo.op == Xsse_SQRTF; +//.. addHRegUse(u, HRmRead, i->Xin.Sse32FLo.src); +//.. addHRegUse(u, unary ? HRmWrite : HRmModify, +//.. i->Xin.Sse32FLo.dst); +//.. return; +//.. case Xin_Sse64Fx2: +//.. vassert(i->Xin.Sse64Fx2.op != Xsse_MOV); +//.. unary = i->Xin.Sse64Fx2.op == Xsse_RCPF +//.. || i->Xin.Sse64Fx2.op == Xsse_RSQRTF +//.. || i->Xin.Sse64Fx2.op == Xsse_SQRTF; +//.. addHRegUse(u, HRmRead, i->Xin.Sse64Fx2.src); +//.. addHRegUse(u, unary ? HRmWrite : HRmModify, +//.. i->Xin.Sse64Fx2.dst); +//.. return; +//.. case Xin_Sse64FLo: +//.. vassert(i->Xin.Sse64FLo.op != Xsse_MOV); +//.. unary = i->Xin.Sse64FLo.op == Xsse_RCPF +//.. || i->Xin.Sse64FLo.op == Xsse_RSQRTF +//.. || i->Xin.Sse64FLo.op == Xsse_SQRTF; +//.. addHRegUse(u, HRmRead, i->Xin.Sse64FLo.src); +//.. addHRegUse(u, unary ? HRmWrite : HRmModify, +//.. i->Xin.Sse64FLo.dst); +//.. return; +//.. case Xin_SseReRg: +//.. if (i->Xin.SseReRg.op == Xsse_XOR +//.. && i->Xin.SseReRg.src == i->Xin.SseReRg.dst) { +//.. /* reg-alloc needs to understand 'xor r,r' as a write of r */ +//.. /* (as opposed to a rite of passage :-) */ +//.. addHRegUse(u, HRmWrite, i->Xin.SseReRg.dst); +//.. } else { +//.. addHRegUse(u, HRmRead, i->Xin.SseReRg.src); +//.. addHRegUse(u, i->Xin.SseReRg.op == Xsse_MOV +//.. ? HRmWrite : HRmModify, +//.. i->Xin.SseReRg.dst); +//.. } +//.. return; +//.. case Xin_SseCMov: +//.. addHRegUse(u, HRmRead, i->Xin.SseCMov.src); +//.. addHRegUse(u, HRmModify, i->Xin.SseCMov.dst); +//.. return; +//.. case Xin_SseShuf: +//.. addHRegUse(u, HRmRead, i->Xin.SseShuf.src); +//.. addHRegUse(u, HRmWrite, i->Xin.SseShuf.dst); +//.. return; + default: + ppPPC32Instr(i); + vpanic("getRegUsage_PPC32Instr"); + } +} + +//.. /* local helper */ +//.. static void mapReg(HRegRemap* m, HReg* r) +//.. { +//.. *r = lookupHRegRemap(m, *r); +//.. } + +void mapRegs_PPC32Instr (HRegRemap* m, PPC32Instr* i) +{ + switch (i->tag) { +//.. case Xin_Alu32R: +//.. mapRegs_X86RMI(m, i->Xin.Alu32R.src); +//.. mapReg(m, &i->Xin.Alu32R.dst); +//.. return; +//.. case Xin_Alu32M: +//.. mapRegs_X86RI(m, i->Xin.Alu32M.src); +//.. mapRegs_X86AMode(m, i->Xin.Alu32M.dst); +//.. return; +//.. case Xin_Sh32: +//.. mapRegs_X86RM(m, i->Xin.Sh32.dst); +//.. return; +//.. case Xin_Test32: +//.. mapRegs_X86RI(m, i->Xin.Test32.src); +//.. mapRegs_X86RM(m, i->Xin.Test32.dst); +//.. return; +//.. case Xin_Unary32: +//.. mapRegs_X86RM(m, i->Xin.Unary32.dst); +//.. return; +//.. case Xin_MulL: +//.. mapRegs_X86RM(m, i->Xin.MulL.src); +//.. return; +//.. case Xin_Div: +//.. mapRegs_X86RM(m, i->Xin.Div.src); +//.. return; +//.. case Xin_Sh3232: +//.. mapReg(m, &i->Xin.Sh3232.src); +//.. mapReg(m, &i->Xin.Sh3232.dst); +//.. return; +//.. case Xin_Push: +//.. mapRegs_X86RMI(m, i->Xin.Push.src); +//.. return; +//.. case Xin_Call: +//.. return; +//.. case Xin_Goto: +//.. mapRegs_X86RI(m, i->Xin.Goto.dst); +//.. return; +//.. case Xin_CMov32: +//.. mapRegs_X86RM(m, i->Xin.CMov32.src); +//.. mapReg(m, &i->Xin.CMov32.dst); +//.. return; +//.. case Xin_LoadEX: +//.. mapRegs_X86AMode(m, i->Xin.LoadEX.src); +//.. mapReg(m, &i->Xin.LoadEX.dst); +//.. return; +//.. case Xin_Store: +//.. mapReg(m, &i->Xin.Store.src); +//.. mapRegs_X86AMode(m, i->Xin.Store.dst); +//.. return; +//.. case Xin_Set32: +//.. mapReg(m, &i->Xin.Set32.dst); +//.. return; +//.. case Xin_Bsfr32: +//.. mapReg(m, &i->Xin.Bsfr32.src); +//.. mapReg(m, &i->Xin.Bsfr32.dst); +//.. return; +//.. case Xin_MFence: +//.. return; +//.. case Xin_FpUnary: +//.. mapReg(m, &i->Xin.FpUnary.src); +//.. mapReg(m, &i->Xin.FpUnary.dst); +//.. return; +//.. case Xin_FpBinary: +//.. mapReg(m, &i->Xin.FpBinary.srcL); +//.. mapReg(m, &i->Xin.FpBinary.srcR); +//.. mapReg(m, &i->Xin.FpBinary.dst); +//.. return; +//.. case Xin_FpLdSt: +//.. mapRegs_X86AMode(m, i->Xin.FpLdSt.addr); +//.. mapReg(m, &i->Xin.FpLdSt.reg); +//.. return; +//.. case Xin_FpLdStI: +//.. mapRegs_X86AMode(m, i->Xin.FpLdStI.addr); +//.. mapReg(m, &i->Xin.FpLdStI.reg); +//.. return; +//.. case Xin_Fp64to32: +//.. mapReg(m, &i->Xin.Fp64to32.src); +//.. mapReg(m, &i->Xin.Fp64to32.dst); +//.. return; +//.. case Xin_FpCMov: +//.. mapReg(m, &i->Xin.FpCMov.src); +//.. mapReg(m, &i->Xin.FpCMov.dst); +//.. return; +//.. case Xin_FpLdStCW: +//.. mapRegs_X86AMode(m, i->Xin.FpLdStCW.addr); +//.. return; +//.. case Xin_FpStSW_AX: +//.. return; +//.. case Xin_FpCmp: +//.. mapReg(m, &i->Xin.FpCmp.srcL); +//.. mapReg(m, &i->Xin.FpCmp.srcR); +//.. mapReg(m, &i->Xin.FpCmp.dst); +//.. return; +//.. case Xin_SseConst: +//.. mapReg(m, &i->Xin.SseConst.dst); +//.. return; +//.. case Xin_SseLdSt: +//.. mapReg(m, &i->Xin.SseLdSt.reg); +//.. mapRegs_X86AMode(m, i->Xin.SseLdSt.addr); +//.. break; +//.. case Xin_SseLdzLO: +//.. mapReg(m, &i->Xin.SseLdzLO.reg); +//.. mapRegs_X86AMode(m, i->Xin.SseLdzLO.addr); +//.. break; +//.. case Xin_Sse32Fx4: +//.. mapReg(m, &i->Xin.Sse32Fx4.src); +//.. mapReg(m, &i->Xin.Sse32Fx4.dst); +//.. return; +//.. case Xin_Sse32FLo: +//.. mapReg(m, &i->Xin.Sse32FLo.src); +//.. mapReg(m, &i->Xin.Sse32FLo.dst); +//.. return; +//.. case Xin_Sse64Fx2: +//.. mapReg(m, &i->Xin.Sse64Fx2.src); +//.. mapReg(m, &i->Xin.Sse64Fx2.dst); +//.. return; +//.. case Xin_Sse64FLo: +//.. mapReg(m, &i->Xin.Sse64FLo.src); +//.. mapReg(m, &i->Xin.Sse64FLo.dst); +//.. return; +//.. case Xin_SseReRg: +//.. mapReg(m, &i->Xin.SseReRg.src); +//.. mapReg(m, &i->Xin.SseReRg.dst); +//.. return; +//.. case Xin_SseCMov: +//.. mapReg(m, &i->Xin.SseCMov.src); +//.. mapReg(m, &i->Xin.SseCMov.dst); +//.. return; +//.. case Xin_SseShuf: +//.. mapReg(m, &i->Xin.SseShuf.src); +//.. mapReg(m, &i->Xin.SseShuf.dst); +//.. return; + default: + ppPPC32Instr(i); + vpanic("mapRegs_PPC32Instr"); + } +} + +/* Figure out if i represents a reg-reg move, and if so assign the + source and destination to *src and *dst. If in doubt say No. Used + by the register allocator to do move coalescing. +*/ +Bool isMove_PPC32Instr ( PPC32Instr* i, HReg* src, HReg* dst ) +{ +//.. /* Moves between integer regs */ +//.. if (i->tag == Xin_Alu32R) { +//.. if (i->Xin.Alu32R.op != Xalu_MOV) +//.. return False; +//.. if (i->Xin.Alu32R.src->tag != Xrmi_Reg) +//.. return False; +//.. *src = i->Xin.Alu32R.src->Xrmi.Reg.reg; +//.. *dst = i->Xin.Alu32R.dst; +//.. return True; +//.. } +//.. /* Moves between FP regs */ +//.. if (i->tag == Xin_FpUnary) { +//.. if (i->Xin.FpUnary.op != Xfp_MOV) +//.. return False; +//.. *src = i->Xin.FpUnary.src; +//.. *dst = i->Xin.FpUnary.dst; +//.. return True; +//.. } +//.. if (i->tag == Xin_SseReRg) { +//.. if (i->Xin.SseReRg.op != Xsse_MOV) +//.. return False; +//.. *src = i->Xin.SseReRg.src; +//.. *dst = i->Xin.SseReRg.dst; +//.. return True; +//.. } + return False; +} + + +/* Generate x86 spill/reload instructions under the direction of the + register allocator. Note it's critical these don't write the + condition codes. */ + +PPC32Instr* genSpill_PPC32 ( HReg rreg, Int offsetB ) +{ vassert(0); +//.. X86AMode* am; +//.. vassert(offsetB >= 0); +//.. vassert(!hregIsVirtual(rreg)); +//.. am = X86AMode_IR(offsetB, hregX86_EBP()); +//.. +//.. switch (hregClass(rreg)) { +//.. case HRcInt32: +//.. return X86Instr_Alu32M ( Xalu_MOV, X86RI_Reg(rreg), am ); +//.. case HRcFlt64: +//.. return X86Instr_FpLdSt ( False/*store*/, 8, rreg, am ); +//.. case HRcVec128: +//.. return X86Instr_SseLdSt ( False/*store*/, rreg, am ); +//.. default: +//.. ppHRegClass(hregClass(rreg)); +//.. vpanic("genSpill_X86: unimplemented regclass"); +//.. } +} + +PPC32Instr* genReload_PPC32 ( HReg rreg, Int offsetB ) +{ vassert(0); +//.. X86AMode* am; +//.. vassert(offsetB >= 0); +//.. vassert(!hregIsVirtual(rreg)); +//.. am = X86AMode_IR(offsetB, hregX86_EBP()); +//.. switch (hregClass(rreg)) { +//.. case HRcInt32: +//.. return X86Instr_Alu32R ( Xalu_MOV, X86RMI_Mem(am), rreg ); +//.. case HRcFlt64: +//.. return X86Instr_FpLdSt ( True/*load*/, 8, rreg, am ); +//.. case HRcVec128: +//.. return X86Instr_SseLdSt ( True/*load*/, rreg, am ); +//.. default: +//.. ppHRegClass(hregClass(rreg)); +//.. vpanic("genReload_X86: unimplemented regclass"); +//.. } +} + + +//.. /* --------- The x86 assembler (bleh.) --------- */ +//.. +//.. static UInt iregNo ( HReg r ) +//.. { +//.. UInt n; +//.. vassert(hregClass(r) == HRcInt32); +//.. vassert(!hregIsVirtual(r)); +//.. n = hregNumber(r); +//.. vassert(n <= 7); +//.. return n; +//.. } +//.. +//.. static UInt fregNo ( HReg r ) +//.. { +//.. UInt n; +//.. vassert(hregClass(r) == HRcFlt64); +//.. vassert(!hregIsVirtual(r)); +//.. n = hregNumber(r); +//.. vassert(n <= 5); +//.. return n; +//.. } +//.. +//.. static UInt vregNo ( HReg r ) +//.. { +//.. UInt n; +//.. vassert(hregClass(r) == HRcVec128); +//.. vassert(!hregIsVirtual(r)); +//.. n = hregNumber(r); +//.. vassert(n <= 7); +//.. return n; +//.. } +//.. +//.. static UChar mkModRegRM ( UChar mod, UChar reg, UChar regmem ) +//.. { +//.. return ((mod & 3) << 6) | ((reg & 7) << 3) | (regmem & 7); +//.. } +//.. +//.. static UChar mkSIB ( Int shift, Int regindex, Int regbase ) +//.. { +//.. return ((shift & 3) << 6) | ((regindex & 7) << 3) | (regbase & 7); +//.. } +//.. +//.. static UChar* emit32 ( UChar* p, UInt w32 ) +//.. { +//.. *p++ = (w32) & 0x000000FF; +//.. *p++ = (w32 >> 8) & 0x000000FF; +//.. *p++ = (w32 >> 16) & 0x000000FF; +//.. *p++ = (w32 >> 24) & 0x000000FF; +//.. return p; +//.. } +//.. +//.. /* Does a sign-extend of the lowest 8 bits give +//.. the original number? */ +//.. static Bool fits8bits ( UInt w32 ) +//.. { +//.. Int i32 = (Int)w32; +//.. return i32 == ((i32 << 24) >> 24); +//.. } +//.. +//.. +//.. /* Forming mod-reg-rm bytes and scale-index-base bytes. +//.. +//.. greg, 0(ereg) | ereg != ESP && ereg != EBP +//.. = 00 greg ereg +//.. +//.. greg, d8(ereg) | ereg != ESP +//.. = 01 greg ereg, d8 +//.. +//.. greg, d32(ereg) | ereg != ESP +//.. = 10 greg ereg, d32 +//.. +//.. greg, d8(%esp) = 01 greg 100, 0x24, d8 +//.. +//.. ----------------------------------------------- +//.. +//.. greg, d8(base,index,scale) +//.. | index != ESP +//.. = 01 greg 100, scale index base, d8 +//.. +//.. greg, d32(base,index,scale) +//.. | index != ESP +//.. = 10 greg 100, scale index base, d32 +//.. */ +//.. static UChar* doAMode_M ( UChar* p, HReg greg, X86AMode* am ) +//.. { +//.. if (am->tag == Xam_IR) { +//.. if (am->Xam.IR.imm == 0 +//.. && am->Xam.IR.reg != hregX86_ESP() +//.. && am->Xam.IR.reg != hregX86_EBP() ) { +//.. *p++ = mkModRegRM(0, iregNo(greg), iregNo(am->Xam.IR.reg)); +//.. return p; +//.. } +//.. if (fits8bits(am->Xam.IR.imm) +//.. && am->Xam.IR.reg != hregX86_ESP()) { +//.. *p++ = mkModRegRM(1, iregNo(greg), iregNo(am->Xam.IR.reg)); +//.. *p++ = am->Xam.IR.imm & 0xFF; +//.. return p; +//.. } +//.. if (am->Xam.IR.reg != hregX86_ESP()) { +//.. *p++ = mkModRegRM(2, iregNo(greg), iregNo(am->Xam.IR.reg)); +//.. p = emit32(p, am->Xam.IR.imm); +//.. return p; +//.. } +//.. if (am->Xam.IR.reg == hregX86_ESP() +//.. && fits8bits(am->Xam.IR.imm)) { +//.. *p++ = mkModRegRM(1, iregNo(greg), 4); +//.. *p++ = 0x24; +//.. *p++ = am->Xam.IR.imm & 0xFF; +//.. return p; +//.. } +//.. ppX86AMode(am); +//.. vpanic("doAMode_M: can't emit amode IR"); +//.. /*NOTREACHED*/ +//.. } +//.. if (am->tag == Xam_IRRS) { +//.. if (fits8bits(am->Xam.IRRS.imm) +//.. && am->Xam.IRRS.index != hregX86_ESP()) { +//.. *p++ = mkModRegRM(1, iregNo(greg), 4); +//.. *p++ = mkSIB(am->Xam.IRRS.shift, am->Xam.IRRS.index, +//.. am->Xam.IRRS.base); +//.. *p++ = am->Xam.IRRS.imm & 0xFF; +//.. return p; +//.. } +//.. if (am->Xam.IRRS.index != hregX86_ESP()) { +//.. *p++ = mkModRegRM(2, iregNo(greg), 4); +//.. *p++ = mkSIB(am->Xam.IRRS.shift, am->Xam.IRRS.index, +//.. am->Xam.IRRS.base); +//.. p = emit32(p, am->Xam.IRRS.imm); +//.. return p; +//.. } +//.. ppX86AMode(am); +//.. vpanic("doAMode_M: can't emit amode IRRS"); +//.. /*NOTREACHED*/ +//.. } +//.. vpanic("doAMode_M: unknown amode"); +//.. /*NOTREACHED*/ +//.. } +//.. +//.. +//.. /* Emit a mod-reg-rm byte when the rm bit denotes a reg. */ +//.. static UChar* doAMode_R ( UChar* p, HReg greg, HReg ereg ) +//.. { +//.. *p++ = mkModRegRM(3, iregNo(greg), iregNo(ereg)); +//.. return p; +//.. } +//.. +//.. +//.. /* Emit ffree %st(7) */ +//.. static UChar* do_ffree_st7 ( UChar* p ) +//.. { +//.. *p++ = 0xDD; +//.. *p++ = 0xC7; +//.. return p; +//.. } +//.. +//.. /* Emit fstp %st(i), 1 <= i <= 7 */ +//.. static UChar* do_fstp_st ( UChar* p, Int i ) +//.. { +//.. vassert(1 <= i && i <= 7); +//.. *p++ = 0xDD; +//.. *p++ = 0xD8+i; +//.. return p; +//.. } +//.. +//.. /* Emit fld %st(i), 0 <= i <= 6 */ +//.. static UChar* do_fld_st ( UChar* p, Int i ) +//.. { +//.. vassert(0 <= i && i <= 6); +//.. *p++ = 0xD9; +//.. *p++ = 0xC0+i; +//.. return p; +//.. } +//.. +//.. /* Emit f %st(0) */ +//.. static UChar* do_fop1_st ( UChar* p, X86FpOp op ) +//.. { +//.. switch (op) { +//.. case Xfp_NEG: *p++ = 0xD9; *p++ = 0xE0; break; +//.. case Xfp_ABS: *p++ = 0xD9; *p++ = 0xE1; break; +//.. case Xfp_SQRT: *p++ = 0xD9; *p++ = 0xFA; break; +//.. case Xfp_ROUND: *p++ = 0xD9; *p++ = 0xFC; break; +//.. case Xfp_SIN: *p++ = 0xD9; *p++ = 0xFE; break; +//.. case Xfp_COS: *p++ = 0xD9; *p++ = 0xFF; break; +//.. case Xfp_2XM1: *p++ = 0xD9; *p++ = 0xF0; break; +//.. case Xfp_MOV: break; +//.. case Xfp_TAN: p = do_ffree_st7(p); /* since fptan pushes 1.0 */ +//.. *p++ = 0xD9; *p++ = 0xF2; /* fptan */ +//.. *p++ = 0xD9; *p++ = 0xF7; /* fincstp */ +//.. break; +//.. default: vpanic("do_fop1_st: unknown op"); +//.. } +//.. return p; +//.. } +//.. +//.. /* Emit f %st(i), 1 <= i <= 5 */ +//.. static UChar* do_fop2_st ( UChar* p, X86FpOp op, Int i ) +//.. { +//.. # define fake(_n) mkHReg((_n), HRcInt32, False) +//.. Int subopc; +//.. switch (op) { +//.. case Xfp_ADD: subopc = 0; break; +//.. case Xfp_SUB: subopc = 4; break; +//.. case Xfp_MUL: subopc = 1; break; +//.. case Xfp_DIV: subopc = 6; break; +//.. default: vpanic("do_fop2_st: unknown op"); +//.. } +//.. *p++ = 0xD8; +//.. p = doAMode_R(p, fake(subopc), fake(i)); +//.. return p; +//.. # undef fake +//.. } +//.. +//.. /* Push a 32-bit word on the stack. The word depends on tags[3:0]; +//.. each byte is either 0x00 or 0xFF depending on the corresponding bit in tags[]. +//.. */ +//.. static UChar* push_word_from_tags ( UChar* p, UShort tags ) +//.. { +//.. UInt w; +//.. vassert(0 == (tags & ~0xF)); +//.. if (tags == 0) { +//.. /* pushl $0x00000000 */ +//.. *p++ = 0x6A; +//.. *p++ = 0x00; +//.. } +//.. else +//.. /* pushl $0xFFFFFFFF */ +//.. if (tags == 0xF) { +//.. *p++ = 0x6A; +//.. *p++ = 0xFF; +//.. } else { +//.. vassert(0); /* awaiting test case */ +//.. w = 0; +//.. if (tags & 1) w |= 0x000000FF; +//.. if (tags & 2) w |= 0x0000FF00; +//.. if (tags & 4) w |= 0x00FF0000; +//.. if (tags & 8) w |= 0xFF000000; +//.. *p++ = 0x68; +//.. p = emit32(p, w); +//.. } +//.. return p; +//.. } + +/* Emit an instruction into buf and return the number of bytes used. + Note that buf is not the insn's final place, and therefore it is + imperative to emit position-independent code. */ + +Int emit_PPC32Instr ( UChar* buf, Int nbuf, PPC32Instr* i ) +{ +//.. UInt irno, opc, opc_rr, subopc_imm, opc_imma, opc_cl, opc_imm, subopc; +//.. +//.. UInt xtra; + UChar* p = &buf[0]; +//.. UChar* ptmp; +//.. vassert(nbuf >= 32); +//.. +//.. /* Wrap an integer as a int register, for use assembling +//.. GrpN insns, in which the greg field is used as a sub-opcode +//.. and does not really contain a register. */ +//.. # define fake(_n) mkHReg((_n), HRcInt32, False) +//.. +//.. /* vex_printf("asm ");ppX86Instr(i); vex_printf("\n"); */ + + switch (i->tag) { + +//.. case Xin_Alu32R: +//.. /* Deal specially with MOV */ +//.. if (i->Xin.Alu32R.op == Xalu_MOV) { +//.. switch (i->Xin.Alu32R.src->tag) { +//.. case Xrmi_Imm: +//.. *p++ = 0xB8 + iregNo(i->Xin.Alu32R.dst); +//.. p = emit32(p, i->Xin.Alu32R.src->Xrmi.Imm.imm32); +//.. goto done; +//.. case Xrmi_Reg: +//.. *p++ = 0x89; +//.. p = doAMode_R(p, i->Xin.Alu32R.src->Xrmi.Reg.reg, +//.. i->Xin.Alu32R.dst); +//.. goto done; +//.. case Xrmi_Mem: +//.. *p++ = 0x8B; +//.. p = doAMode_M(p, i->Xin.Alu32R.dst, +//.. i->Xin.Alu32R.src->Xrmi.Mem.am); +//.. goto done; +//.. default: +//.. goto bad; +//.. } +//.. } +//.. /* MUL */ +//.. if (i->Xin.Alu32R.op == Xalu_MUL) { +//.. switch (i->Xin.Alu32R.src->tag) { +//.. case Xrmi_Reg: +//.. *p++ = 0x0F; +//.. *p++ = 0xAF; +//.. p = doAMode_R(p, i->Xin.Alu32R.dst, +//.. i->Xin.Alu32R.src->Xrmi.Reg.reg); +//.. goto done; +//.. case Xrmi_Mem: +//.. *p++ = 0x0F; +//.. *p++ = 0xAF; +//.. p = doAMode_M(p, i->Xin.Alu32R.dst, +//.. i->Xin.Alu32R.src->Xrmi.Mem.am); +//.. goto done; +//.. case Xrmi_Imm: +//.. if (fits8bits(i->Xin.Alu32R.src->Xrmi.Imm.imm32)) { +//.. *p++ = 0x6B; +//.. p = doAMode_R(p, i->Xin.Alu32R.dst, i->Xin.Alu32R.dst); +//.. *p++ = 0xFF & i->Xin.Alu32R.src->Xrmi.Imm.imm32; +//.. } else { +//.. *p++ = 0x69; +//.. p = doAMode_R(p, i->Xin.Alu32R.dst, i->Xin.Alu32R.dst); +//.. p = emit32(p, i->Xin.Alu32R.src->Xrmi.Imm.imm32); +//.. } +//.. goto done; +//.. default: +//.. goto bad; +//.. } +//.. } +//.. /* ADD/SUB/ADC/SBB/AND/OR/XOR/CMP */ +//.. opc = opc_rr = subopc_imm = opc_imma = 0; +//.. switch (i->Xin.Alu32R.op) { +//.. case Xalu_ADC: opc = 0x13; opc_rr = 0x11; +//.. subopc_imm = 2; opc_imma = 0x15; break; +//.. case Xalu_ADD: opc = 0x03; opc_rr = 0x01; +//.. subopc_imm = 0; opc_imma = 0x05; break; +//.. case Xalu_SUB: opc = 0x2B; opc_rr = 0x29; +//.. subopc_imm = 5; opc_imma = 0x2D; break; +//.. case Xalu_SBB: opc = 0x1B; opc_rr = 0x19; +//.. subopc_imm = 3; opc_imma = 0x1D; break; +//.. case Xalu_AND: opc = 0x23; opc_rr = 0x21; +//.. subopc_imm = 4; opc_imma = 0x25; break; +//.. case Xalu_XOR: opc = 0x33; opc_rr = 0x31; +//.. subopc_imm = 6; opc_imma = 0x35; break; +//.. case Xalu_OR: opc = 0x0B; opc_rr = 0x09; +//.. subopc_imm = 1; opc_imma = 0x0D; break; +//.. case Xalu_CMP: opc = 0x3B; opc_rr = 0x39; +//.. subopc_imm = 7; opc_imma = 0x3D; break; +//.. default: goto bad; +//.. } +//.. switch (i->Xin.Alu32R.src->tag) { +//.. case Xrmi_Imm: +//.. if (i->Xin.Alu32R.dst == hregX86_EAX() +//.. && !fits8bits(i->Xin.Alu32R.src->Xrmi.Imm.imm32)) { +//.. *p++ = opc_imma; +//.. p = emit32(p, i->Xin.Alu32R.src->Xrmi.Imm.imm32); +//.. } else +//.. if (fits8bits(i->Xin.Alu32R.src->Xrmi.Imm.imm32)) { +//.. *p++ = 0x83; +//.. p = doAMode_R(p, fake(subopc_imm), i->Xin.Alu32R.dst); +//.. *p++ = 0xFF & i->Xin.Alu32R.src->Xrmi.Imm.imm32; +//.. } else { +//.. *p++ = 0x81; +//.. p = doAMode_R(p, fake(subopc_imm), i->Xin.Alu32R.dst); +//.. p = emit32(p, i->Xin.Alu32R.src->Xrmi.Imm.imm32); +//.. } +//.. goto done; +//.. case Xrmi_Reg: +//.. *p++ = opc_rr; +//.. p = doAMode_R(p, i->Xin.Alu32R.src->Xrmi.Reg.reg, +//.. i->Xin.Alu32R.dst); +//.. goto done; +//.. case Xrmi_Mem: +//.. *p++ = opc; +//.. p = doAMode_M(p, i->Xin.Alu32R.dst, +//.. i->Xin.Alu32R.src->Xrmi.Mem.am); +//.. goto done; +//.. default: +//.. goto bad; +//.. } +//.. break; +//.. +//.. case Xin_Alu32M: +//.. /* Deal specially with MOV */ +//.. if (i->Xin.Alu32M.op == Xalu_MOV) { +//.. switch (i->Xin.Alu32M.src->tag) { +//.. case Xri_Reg: +//.. *p++ = 0x89; +//.. p = doAMode_M(p, i->Xin.Alu32M.src->Xri.Reg.reg, +//.. i->Xin.Alu32M.dst); +//.. goto done; +//.. case Xri_Imm: +//.. *p++ = 0xC7; +//.. p = doAMode_M(p, fake(0), i->Xin.Alu32M.dst); +//.. p = emit32(p, i->Xin.Alu32M.src->Xri.Imm.imm32); +//.. goto done; +//.. default: +//.. goto bad; +//.. } +//.. } +//.. /* ADD/SUB/ADC/SBB/AND/OR/XOR/CMP. MUL is not +//.. allowed here. */ +//.. opc = subopc_imm = opc_imma = 0; +//.. switch (i->Xin.Alu32M.op) { +//.. case Xalu_ADD: opc = 0x01; subopc_imm = 0; break; +//.. case Xalu_SUB: opc = 0x29; subopc_imm = 5; break; +//.. default: goto bad; +//.. } +//.. switch (i->Xin.Alu32M.src->tag) { +//.. case Xri_Reg: +//.. *p++ = opc; +//.. p = doAMode_M(p, i->Xin.Alu32M.src->Xri.Reg.reg, +//.. i->Xin.Alu32M.dst); +//.. goto done; +//.. case Xri_Imm: +//.. if (fits8bits(i->Xin.Alu32M.src->Xri.Imm.imm32)) { +//.. *p++ = 0x83; +//.. p = doAMode_M(p, fake(subopc_imm), i->Xin.Alu32M.dst); +//.. *p++ = 0xFF & i->Xin.Alu32M.src->Xri.Imm.imm32; +//.. goto done; +//.. } else { +//.. *p++ = 0x81; +//.. p = doAMode_M(p, fake(subopc_imm), i->Xin.Alu32M.dst); +//.. p = emit32(p, i->Xin.Alu32M.src->Xri.Imm.imm32); +//.. goto done; +//.. } +//.. default: +//.. goto bad; +//.. } +//.. break; +//.. +//.. case Xin_Sh32: +//.. opc_cl = opc_imm = subopc = 0; +//.. switch (i->Xin.Sh32.op) { +//.. case Xsh_SHR: opc_cl = 0xD3; opc_imm = 0xC1; subopc = 5; break; +//.. case Xsh_SAR: opc_cl = 0xD3; opc_imm = 0xC1; subopc = 7; break; +//.. case Xsh_SHL: opc_cl = 0xD3; opc_imm = 0xC1; subopc = 4; break; +//.. default: goto bad; +//.. } +//.. if (i->Xin.Sh32.src == 0) { +//.. *p++ = opc_cl; +//.. switch (i->Xin.Sh32.dst->tag) { +//.. case Xrm_Reg: +//.. p = doAMode_R(p, fake(subopc), +//.. i->Xin.Sh32.dst->Xrm.Reg.reg); +//.. goto done; +//.. default: +//.. goto bad; +//.. } +//.. } else { +//.. *p++ = opc_imm; +//.. switch (i->Xin.Sh32.dst->tag) { +//.. case Xrm_Reg: +//.. p = doAMode_R(p, fake(subopc), +//.. i->Xin.Sh32.dst->Xrm.Reg.reg); +//.. *p++ = (UChar)(i->Xin.Sh32.src); +//.. goto done; +//.. default: +//.. goto bad; +//.. } +//.. } +//.. break; +//.. +//.. case Xin_Test32: +//.. if (i->Xin.Test32.src->tag == Xri_Imm +//.. && i->Xin.Test32.dst->tag == Xrm_Reg) { +//.. /* testl $imm32, %reg */ +//.. *p++ = 0xF7; +//.. p = doAMode_R(p, fake(0), i->Xin.Test32.dst->Xrm.Reg.reg); +//.. p = emit32(p, i->Xin.Test32.src->Xri.Imm.imm32); +//.. goto done; +//.. } +//.. break; +//.. +//.. case Xin_Unary32: +//.. if (i->Xin.Unary32.op == Xun_NOT) { +//.. *p++ = 0xF7; +//.. if (i->Xin.Unary32.dst->tag == Xrm_Reg) { +//.. p = doAMode_R(p, fake(2), i->Xin.Unary32.dst->Xrm.Reg.reg); +//.. goto done; +//.. } else { +//.. goto bad; +//.. } +//.. } +//.. if (i->Xin.Unary32.op == Xun_NEG) { +//.. *p++ = 0xF7; +//.. if (i->Xin.Unary32.dst->tag == Xrm_Reg) { +//.. p = doAMode_R(p, fake(3), i->Xin.Unary32.dst->Xrm.Reg.reg); +//.. goto done; +//.. } else { +//.. goto bad; +//.. } +//.. } +//.. break; +//.. +//.. case Xin_MulL: +//.. subopc = i->Xin.MulL.syned ? 5 : 4; +//.. if (i->Xin.MulL.ssz == Xss_32) { +//.. *p++ = 0xF7; +//.. switch (i->Xin.MulL.src->tag) { +//.. case Xrm_Mem: +//.. p = doAMode_M(p, fake(subopc), +//.. i->Xin.MulL.src->Xrm.Mem.am); +//.. goto done; +//.. case Xrm_Reg: +//.. p = doAMode_R(p, fake(subopc), +//.. i->Xin.MulL.src->Xrm.Reg.reg); +//.. goto done; +//.. default: +//.. goto bad; +//.. } +//.. } +//.. break; +//.. +//.. case Xin_Div: +//.. subopc = i->Xin.Div.syned ? 7 : 6; +//.. if (i->Xin.Div.ssz == Xss_32) { +//.. *p++ = 0xF7; +//.. switch (i->Xin.Div.src->tag) { +//.. case Xrm_Mem: +//.. p = doAMode_M(p, fake(subopc), +//.. i->Xin.Div.src->Xrm.Mem.am); +//.. goto done; +//.. case Xrm_Reg: +//.. p = doAMode_R(p, fake(subopc), +//.. i->Xin.Div.src->Xrm.Reg.reg); +//.. goto done; +//.. default: +//.. goto bad; +//.. } +//.. } +//.. break; +//.. +//.. case Xin_Sh3232: +//.. vassert(i->Xin.Sh3232.op == Xsh_SHL || i->Xin.Sh3232.op == Xsh_SHR); +//.. if (i->Xin.Sh3232.amt == 0) { +//.. /* shldl/shrdl by %cl */ +//.. *p++ = 0x0F; +//.. if (i->Xin.Sh3232.op == Xsh_SHL) { +//.. *p++ = 0xA5; +//.. } else { +//.. *p++ = 0xAD; +//.. } +//.. p = doAMode_R(p, i->Xin.Sh3232.src, i->Xin.Sh3232.dst); +//.. goto done; +//.. } +//.. break; +//.. +//.. case Xin_Push: +//.. switch (i->Xin.Push.src->tag) { +//.. case Xrmi_Mem: +//.. *p++ = 0xFF; +//.. p = doAMode_M(p, fake(6), i->Xin.Push.src->Xrmi.Mem.am); +//.. goto done; +//.. case Xrmi_Imm: +//.. *p++ = 0x68; +//.. p = emit32(p, i->Xin.Push.src->Xrmi.Imm.imm32); +//.. goto done; +//.. case Xrmi_Reg: +//.. *p++ = 0x50 + iregNo(i->Xin.Push.src->Xrmi.Reg.reg); +//.. goto done; +//.. default: +//.. goto bad; +//.. } +//.. +//.. case Xin_Call: +//.. /* See detailed comment for Xin_Call in getRegUsage_X86Instr above +//.. for explanation of this. */ +//.. switch (i->Xin.Call.regparms) { +//.. case 0: irno = iregNo(hregX86_EAX()); break; +//.. case 1: irno = iregNo(hregX86_EDX()); break; +//.. case 2: irno = iregNo(hregX86_ECX()); break; +//.. case 3: irno = iregNo(hregX86_EDI()); break; +//.. default: vpanic(" emit_X86Instr:call:regparms"); +//.. } +//.. /* jump over the following two insns if the condition does not +//.. hold */ +//.. if (i->Xin.Call.cond != Xcc_ALWAYS) { +//.. *p++ = 0x70 + (0xF & (i->Xin.Call.cond ^ 1)); +//.. *p++ = 0x07; /* 7 bytes in the next two insns */ +//.. } +//.. /* movl $target, %tmp */ +//.. *p++ = 0xB8 + irno; +//.. p = emit32(p, i->Xin.Call.target); +//.. /* call *%tmp */ +//.. *p++ = 0xFF; +//.. *p++ = 0xD0 + irno; +//.. goto done; +//.. +//.. case Xin_Goto: +//.. /* Use ptmp for backpatching conditional jumps. */ +//.. ptmp = NULL; +//.. +//.. /* First off, if this is conditional, create a conditional +//.. jump over the rest of it. */ +//.. if (i->Xin.Goto.cond != Xcc_ALWAYS) { +//.. /* jmp fwds if !condition */ +//.. *p++ = 0x70 + (i->Xin.Goto.cond ^ 1); +//.. ptmp = p; /* fill in this bit later */ +//.. *p++ = 0; /* # of bytes to jump over; don't know how many yet. */ +//.. } +//.. +//.. /* If a non-boring, set %ebp (the guest state pointer) +//.. appropriately. */ +//.. /* movl $magic_number, %ebp */ +//.. switch (i->Xin.Goto.jk) { +//.. case Ijk_ClientReq: +//.. *p++ = 0xBD; +//.. p = emit32(p, VEX_TRC_JMP_CLIENTREQ); break; +//.. case Ijk_Syscall: +//.. *p++ = 0xBD; +//.. p = emit32(p, VEX_TRC_JMP_SYSCALL); break; +//.. case Ijk_Yield: +//.. *p++ = 0xBD; +//.. p = emit32(p, VEX_TRC_JMP_YIELD); break; +//.. case Ijk_EmWarn: +//.. *p++ = 0xBD; +//.. p = emit32(p, VEX_TRC_JMP_EMWARN); break; +//.. case Ijk_MapFail: +//.. *p++ = 0xBD; +//.. p = emit32(p, VEX_TRC_JMP_MAPFAIL); break; +//.. case Ijk_NoDecode: +//.. *p++ = 0xBD; +//.. p = emit32(p, VEX_TRC_JMP_NODECODE); break; +//.. case Ijk_Ret: +//.. case Ijk_Call: +//.. case Ijk_Boring: +//.. break; +//.. default: +//.. ppIRJumpKind(i->Xin.Goto.jk); +//.. vpanic("emit_X86Instr.Xin_Goto: unknown jump kind"); +//.. } +//.. +//.. /* Get the destination address into %eax */ +//.. if (i->Xin.Goto.dst->tag == Xri_Imm) { +//.. /* movl $immediate, %eax ; ret */ +//.. *p++ = 0xB8; +//.. p = emit32(p, i->Xin.Goto.dst->Xri.Imm.imm32); +//.. } else { +//.. vassert(i->Xin.Goto.dst->tag == Xri_Reg); +//.. /* movl %reg, %eax ; ret */ +//.. if (i->Xin.Goto.dst->Xri.Reg.reg != hregX86_EAX()) { +//.. *p++ = 0x89; +//.. p = doAMode_R(p, i->Xin.Goto.dst->Xri.Reg.reg, hregX86_EAX()); +//.. } +//.. } +//.. +//.. /* ret */ +//.. *p++ = 0xC3; +//.. +//.. /* Fix up the conditional jump, if there was one. */ +//.. if (i->Xin.Goto.cond != Xcc_ALWAYS) { +//.. Int delta = p - ptmp; +//.. vassert(delta > 0 && delta < 20); +//.. *ptmp = (UChar)(delta-1); +//.. } +//.. goto done; +//.. +//.. case Xin_CMov32: +//.. vassert(i->Xin.CMov32.cond != Xcc_ALWAYS); +//.. #if 0 +//.. /* This generates cmov, which is illegal on P54/P55. */ +//.. *p++ = 0x0F; +//.. *p++ = 0x40 + i->Xin.CMov32.cond; +//.. if (i->Xin.CMov32.src->tag == Xrm_Reg) { +//.. p = doAMode_R(p, i->Xin.CMov32.dst, i->Xin.CMov32.src->Xrm.Reg.reg); +//.. goto done; +//.. } +//.. if (i->Xin.CMov32.src->tag == Xrm_Mem) { +//.. p = doAMode_M(p, i->Xin.CMov32.dst, i->Xin.CMov32.src->Xrm.Mem.am); +//.. goto done; +//.. } +//.. #else +//.. /* P5 friendly version: conditional jump over an unconditional +//.. move. */ +//.. /* jmp fwds if !condition */ +//.. *p++ = 0x70 + (i->Xin.CMov32.cond ^ 1); +//.. *p++ = 0; /* # of bytes in the next bit, which we don't know yet */ +//.. ptmp = p; +//.. +//.. switch (i->Xin.CMov32.src->tag) { +//.. case Xrm_Reg: +//.. /* Big sigh. This is movl E -> G ... */ +//.. *p++ = 0x89; +//.. p = doAMode_R(p, i->Xin.CMov32.src->Xrm.Reg.reg, +//.. i->Xin.CMov32.dst); +//.. +//.. break; +//.. case Xrm_Mem: +//.. /* ... whereas this is movl G -> E. That's why the args +//.. to doAMode_R appear to be the wrong way round in the +//.. Xrm_Reg case. */ +//.. *p++ = 0x8B; +//.. p = doAMode_M(p, i->Xin.CMov32.dst, +//.. i->Xin.CMov32.src->Xrm.Mem.am); +//.. break; +//.. default: +//.. goto bad; +//.. } +//.. /* Fill in the jump offset. */ +//.. *(ptmp-1) = p - ptmp; +//.. goto done; +//.. #endif +//.. break; +//.. +//.. case Xin_LoadEX: +//.. if (i->Xin.LoadEX.szSmall == 1 && !i->Xin.LoadEX.syned) { +//.. /* movzbl */ +//.. *p++ = 0x0F; +//.. *p++ = 0xB6; +//.. p = doAMode_M(p, i->Xin.LoadEX.dst, i->Xin.LoadEX.src); +//.. goto done; +//.. } +//.. if (i->Xin.LoadEX.szSmall == 2 && !i->Xin.LoadEX.syned) { +//.. /* movzwl */ +//.. *p++ = 0x0F; +//.. *p++ = 0xB7; +//.. p = doAMode_M(p, i->Xin.LoadEX.dst, i->Xin.LoadEX.src); +//.. goto done; +//.. } +//.. break; +//.. +//.. case Xin_Set32: +//.. /* Make the destination register be 1 or 0, depending on whether +//.. the relevant condition holds. We have to dodge and weave +//.. when the destination is %esi or %edi as we cannot directly +//.. emit the native 'setb %reg' for those. Further complication: +//.. the top 24 bits of the destination should be forced to zero, +//.. but doing 'xor %r,%r' kills the flag(s) we are about to read. +//.. Sigh. So start off my moving $0 into the dest. */ +//.. +//.. /* Do we need to swap in %eax? */ +//.. if (iregNo(i->Xin.Set32.dst) >= 4) { +//.. /* xchg %eax, %dst */ +//.. *p++ = 0x90 + iregNo(i->Xin.Set32.dst); +//.. /* movl $0, %eax */ +//.. *p++ = 0xB8 + iregNo(hregX86_EAX()); +//.. p = emit32(p, 0); +//.. /* setb lo8(%eax) */ +//.. *p++ = 0x0F; +//.. *p++ = 0x90 + (UChar)(i->Xin.Set32.cond); +//.. p = doAMode_R(p, fake(0), hregX86_EAX()); +//.. /* xchg %eax, %dst */ +//.. *p++ = 0x90 + iregNo(i->Xin.Set32.dst); +//.. } else { +//.. /* movl $0, %dst */ +//.. *p++ = 0xB8 + iregNo(i->Xin.Set32.dst); +//.. p = emit32(p, 0); +//.. /* setb lo8(%dst) */ +//.. *p++ = 0x0F; +//.. *p++ = 0x90 + (UChar)(i->Xin.Set32.cond); +//.. p = doAMode_R(p, fake(0), i->Xin.Set32.dst); +//.. } +//.. goto done; +//.. +//.. case Xin_Bsfr32: +//.. *p++ = 0x0F; +//.. if (i->Xin.Bsfr32.isFwds) { +//.. *p++ = 0xBC; +//.. } else { +//.. *p++ = 0xBD; +//.. } +//.. p = doAMode_R(p, i->Xin.Bsfr32.dst, i->Xin.Bsfr32.src); +//.. goto done; +//.. +//.. case Xin_MFence: +//.. /* see comment in hdefs.h re this insn */ +//.. if (0) vex_printf("EMIT FENCE\n"); +//.. switch (i->Xin.MFence.subarch) { +//.. case VexSubArchX86_sse0: +//.. vassert(0); /* awaiting test case */ +//.. /* lock addl $0,0(%esp) */ +//.. *p++ = 0xF0; *p++ = 0x83; *p++ = 0x44; +//.. *p++ = 0x24; *p++ = 0x00; *p++ = 0x00; +//.. goto done; +//.. case VexSubArchX86_sse1: +//.. /* sfence */ +//.. *p++ = 0x0F; *p++ = 0xAE; *p++ = 0xF8; +//.. /* lock addl $0,0(%esp) */ +//.. *p++ = 0xF0; *p++ = 0x83; *p++ = 0x44; +//.. *p++ = 0x24; *p++ = 0x00; *p++ = 0x00; +//.. goto done; +//.. case VexSubArchX86_sse2: +//.. /* mfence */ +//.. *p++ = 0x0F; *p++ = 0xAE; *p++ = 0xF0; +//.. goto done; +//.. default: +//.. vpanic("emit_X86Instr:mfence:subarch"); +//.. } +//.. break; +//.. +//.. case Xin_Store: +//.. if (i->Xin.Store.sz == 2) { +//.. /* This case, at least, is simple, given that we can +//.. reference the low 16 bits of any integer register. */ +//.. *p++ = 0x66; +//.. *p++ = 0x89; +//.. p = doAMode_M(p, i->Xin.Store.src, i->Xin.Store.dst); +//.. goto done; +//.. } +//.. +//.. if (i->Xin.Store.sz == 1) { +//.. /* We have to do complex dodging and weaving if src is not +//.. the low 8 bits of %eax/%ebx/%ecx/%edx. */ +//.. if (iregNo(i->Xin.Store.src) < 4) { +//.. /* we're OK, can do it directly */ +//.. *p++ = 0x88; +//.. p = doAMode_M(p, i->Xin.Store.src, i->Xin.Store.dst); +//.. goto done; +//.. } else { +//.. /* Bleh. This means the source is %edi or %esi. Since +//.. the address mode can only mention three registers, at +//.. least one of %eax/%ebx/%ecx/%edx must be available to +//.. temporarily swap the source into, so the store can +//.. happen. So we have to look at the regs mentioned +//.. in the amode. */ +//.. HReg swap = INVALID_HREG; +//.. HReg eax = hregX86_EAX(), ebx = hregX86_EBX(), +//.. ecx = hregX86_ECX(), edx = hregX86_EDX(); +//.. Bool a_ok = True, b_ok = True, c_ok = True, d_ok = True; +//.. HRegUsage u; +//.. Int j; +//.. initHRegUsage(&u); +//.. addRegUsage_X86AMode(&u, i->Xin.Store.dst); +//.. for (j = 0; j < u.n_used; j++) { +//.. HReg r = u.hreg[j]; +//.. if (r == eax) a_ok = False; +//.. if (r == ebx) b_ok = False; +//.. if (r == ecx) c_ok = False; +//.. if (r == edx) d_ok = False; +//.. } +//.. if (a_ok) swap = eax; +//.. if (b_ok) swap = ebx; +//.. if (c_ok) swap = ecx; +//.. if (d_ok) swap = edx; +//.. vassert(swap != INVALID_HREG); +//.. /* xchgl %source, %swap. Could do better if swap is %eax. */ +//.. *p++ = 0x87; +//.. p = doAMode_R(p, i->Xin.Store.src, swap); +//.. /* movb lo8{%swap}, (dst) */ +//.. *p++ = 0x88; +//.. p = doAMode_M(p, swap, i->Xin.Store.dst); +//.. /* xchgl %source, %swap. Could do better if swap is %eax. */ +//.. *p++ = 0x87; +//.. p = doAMode_R(p, i->Xin.Store.src, swap); +//.. goto done; +//.. } +//.. } /* if (i->Xin.Store.sz == 1) */ +//.. break; +//.. +//.. case Xin_FpUnary: +//.. /* gop %src, %dst +//.. --> ffree %st7 ; fld %st(src) ; fop %st(0) ; fstp %st(1+dst) +//.. */ +//.. p = do_ffree_st7(p); +//.. p = do_fld_st(p, 0+hregNumber(i->Xin.FpUnary.src)); +//.. p = do_fop1_st(p, i->Xin.FpUnary.op); +//.. p = do_fstp_st(p, 1+hregNumber(i->Xin.FpUnary.dst)); +//.. goto done; +//.. +//.. case Xin_FpBinary: +//.. if (i->Xin.FpBinary.op == Xfp_YL2X +//.. || i->Xin.FpBinary.op == Xfp_YL2XP1) { +//.. /* Have to do this specially. */ +//.. /* ffree %st7 ; fld %st(srcL) ; +//.. ffree %st7 ; fld %st(srcR+1) ; fyl2x{p1} ; fstp(1+dst) */ +//.. p = do_ffree_st7(p); +//.. p = do_fld_st(p, 0+hregNumber(i->Xin.FpBinary.srcL)); +//.. p = do_ffree_st7(p); +//.. p = do_fld_st(p, 1+hregNumber(i->Xin.FpBinary.srcR)); +//.. *p++ = 0xD9; +//.. *p++ = i->Xin.FpBinary.op==Xfp_YL2X ? 0xF1 : 0xF9; +//.. p = do_fstp_st(p, 1+hregNumber(i->Xin.FpBinary.dst)); +//.. goto done; +//.. } +//.. if (i->Xin.FpBinary.op == Xfp_ATAN) { +//.. /* Have to do this specially. */ +//.. /* ffree %st7 ; fld %st(srcL) ; +//.. ffree %st7 ; fld %st(srcR+1) ; fpatan ; fstp(1+dst) */ +//.. p = do_ffree_st7(p); +//.. p = do_fld_st(p, 0+hregNumber(i->Xin.FpBinary.srcL)); +//.. p = do_ffree_st7(p); +//.. p = do_fld_st(p, 1+hregNumber(i->Xin.FpBinary.srcR)); +//.. *p++ = 0xD9; *p++ = 0xF3; +//.. p = do_fstp_st(p, 1+hregNumber(i->Xin.FpBinary.dst)); +//.. goto done; +//.. } +//.. if (i->Xin.FpBinary.op == Xfp_PREM +//.. || i->Xin.FpBinary.op == Xfp_PREM1 +//.. || i->Xin.FpBinary.op == Xfp_SCALE) { +//.. /* Have to do this specially. */ +//.. /* ffree %st7 ; fld %st(srcR) ; +//.. ffree %st7 ; fld %st(srcL+1) ; fprem/fprem1/fscale ; fstp(2+dst) ; +//.. fincstp ; ffree %st7 */ +//.. p = do_ffree_st7(p); +//.. p = do_fld_st(p, 0+hregNumber(i->Xin.FpBinary.srcR)); +//.. p = do_ffree_st7(p); +//.. p = do_fld_st(p, 1+hregNumber(i->Xin.FpBinary.srcL)); +//.. *p++ = 0xD9; +//.. switch (i->Xin.FpBinary.op) { +//.. case Xfp_PREM: *p++ = 0xF8; break; +//.. case Xfp_PREM1: *p++ = 0xF5; break; +//.. case Xfp_SCALE: *p++ = 0xFD; break; +//.. default: vpanic("emitX86Instr(FpBinary,PREM/PREM1/SCALE)"); +//.. } +//.. p = do_fstp_st(p, 2+hregNumber(i->Xin.FpBinary.dst)); +//.. *p++ = 0xD9; *p++ = 0xF7; +//.. p = do_ffree_st7(p); +//.. goto done; +//.. } +//.. /* General case */ +//.. /* gop %srcL, %srcR, %dst +//.. --> ffree %st7 ; fld %st(srcL) ; fop %st(1+srcR) ; fstp %st(1+dst) +//.. */ +//.. p = do_ffree_st7(p); +//.. p = do_fld_st(p, 0+hregNumber(i->Xin.FpBinary.srcL)); +//.. p = do_fop2_st(p, i->Xin.FpBinary.op, +//.. 1+hregNumber(i->Xin.FpBinary.srcR)); +//.. p = do_fstp_st(p, 1+hregNumber(i->Xin.FpBinary.dst)); +//.. goto done; +//.. +//.. case Xin_FpLdSt: +//.. vassert(i->Xin.FpLdSt.sz == 4 || i->Xin.FpLdSt.sz == 8); +//.. if (i->Xin.FpLdSt.isLoad) { +//.. /* Load from memory into %fakeN. +//.. --> ffree %st(7) ; fld{s/l} amode ; fstp st(N+1) +//.. */ +//.. p = do_ffree_st7(p); +//.. *p++ = i->Xin.FpLdSt.sz==4 ? 0xD9 : 0xDD; +//.. p = doAMode_M(p, fake(0)/*subopcode*/, i->Xin.FpLdSt.addr); +//.. p = do_fstp_st(p, 1+hregNumber(i->Xin.FpLdSt.reg)); +//.. goto done; +//.. } else { +//.. /* Store from %fakeN into memory. +//.. --> ffree %st(7) ; fld st(N) ; fstp{l|s} amode +//.. */ +//.. p = do_ffree_st7(p); +//.. p = do_fld_st(p, 0+hregNumber(i->Xin.FpLdSt.reg)); +//.. *p++ = i->Xin.FpLdSt.sz==4 ? 0xD9 : 0xDD; +//.. p = doAMode_M(p, fake(3)/*subopcode*/, i->Xin.FpLdSt.addr); +//.. goto done; +//.. } +//.. break; +//.. +//.. case Xin_FpLdStI: +//.. if (i->Xin.FpLdStI.isLoad) { +//.. /* Load from memory into %fakeN, converting from an int. +//.. --> ffree %st(7) ; fild{w/l/ll} amode ; fstp st(N+1) +//.. */ +//.. switch (i->Xin.FpLdStI.sz) { +//.. case 8: opc = 0xDF; subopc_imm = 5; break; +//.. case 4: opc = 0xDB; subopc_imm = 0; break; +//.. case 2: vassert(0); opc = 0xDF; subopc_imm = 0; break; +//.. default: vpanic("emitX86Instr(Xin_FpLdStI-load)"); +//.. } +//.. p = do_ffree_st7(p); +//.. *p++ = opc; +//.. p = doAMode_M(p, fake(subopc_imm)/*subopcode*/, i->Xin.FpLdStI.addr); +//.. p = do_fstp_st(p, 1+hregNumber(i->Xin.FpLdStI.reg)); +//.. goto done; +//.. } else { +//.. /* Store from %fakeN into memory, converting to an int. +//.. --> ffree %st(7) ; fld st(N) ; fistp{w/l/ll} amode +//.. */ +//.. switch (i->Xin.FpLdStI.sz) { +//.. case 8: opc = 0xDF; subopc_imm = 7; break; +//.. case 4: opc = 0xDB; subopc_imm = 3; break; +//.. case 2: opc = 0xDF; subopc_imm = 3; break; +//.. default: vpanic("emitX86Instr(Xin_FpLdStI-store)"); +//.. } +//.. p = do_ffree_st7(p); +//.. p = do_fld_st(p, 0+hregNumber(i->Xin.FpLdStI.reg)); +//.. *p++ = opc; +//.. p = doAMode_M(p, fake(subopc_imm)/*subopcode*/, i->Xin.FpLdStI.addr); +//.. goto done; +//.. } +//.. break; +//.. +//.. case Xin_Fp64to32: +//.. /* ffree %st7 ; fld %st(src) */ +//.. p = do_ffree_st7(p); +//.. p = do_fld_st(p, 0+fregNo(i->Xin.Fp64to32.src)); +//.. /* subl $4, %esp */ +//.. *p++ = 0x83; *p++ = 0xEC; *p++ = 0x04; +//.. /* fstps (%esp) */ +//.. *p++ = 0xD9; *p++ = 0x1C; *p++ = 0x24; +//.. /* flds (%esp) */ +//.. *p++ = 0xD9; *p++ = 0x04; *p++ = 0x24; +//.. /* addl $4, %esp */ +//.. *p++ = 0x83; *p++ = 0xC4; *p++ = 0x04; +//.. /* fstp %st(1+dst) */ +//.. p = do_fstp_st(p, 1+fregNo(i->Xin.Fp64to32.dst)); +//.. goto done; +//.. +//.. case Xin_FpCMov: +//.. /* jmp fwds if !condition */ +//.. *p++ = 0x70 + (i->Xin.FpCMov.cond ^ 1); +//.. *p++ = 0; /* # of bytes in the next bit, which we don't know yet */ +//.. ptmp = p; +//.. +//.. /* ffree %st7 ; fld %st(src) ; fstp %st(1+dst) */ +//.. p = do_ffree_st7(p); +//.. p = do_fld_st(p, 0+fregNo(i->Xin.FpCMov.src)); +//.. p = do_fstp_st(p, 1+fregNo(i->Xin.FpCMov.dst)); +//.. +//.. /* Fill in the jump offset. */ +//.. *(ptmp-1) = p - ptmp; +//.. goto done; +//.. +//.. case Xin_FpLdStCW: +//.. if (i->Xin.FpLdStCW.isLoad) { +//.. *p++ = 0xD9; +//.. p = doAMode_M(p, fake(5)/*subopcode*/, i->Xin.FpLdStCW.addr); +//.. } else { +//.. vassert(0); +//.. } +//.. goto done; +//.. +//.. case Xin_FpStSW_AX: +//.. /* note, this emits fnstsw %ax, not fstsw %ax */ +//.. *p++ = 0xDF; +//.. *p++ = 0xE0; +//.. goto done; +//.. +//.. case Xin_FpCmp: +//.. /* gcmp %fL, %fR, %dst +//.. -> ffree %st7; fpush %fL ; fucomp %(fR+1) ; +//.. fnstsw %ax ; movl %eax, %dst +//.. */ +//.. /* ffree %st7 */ +//.. p = do_ffree_st7(p); +//.. /* fpush %fL */ +//.. p = do_fld_st(p, 0+fregNo(i->Xin.FpCmp.srcL)); +//.. /* fucomp %(fR+1) */ +//.. *p++ = 0xDD; +//.. *p++ = 0xE8 + (7 & (1+fregNo(i->Xin.FpCmp.srcR))); +//.. /* fnstsw %ax */ +//.. *p++ = 0xDF; +//.. *p++ = 0xE0; +//.. /* movl %eax, %dst */ +//.. *p++ = 0x89; +//.. p = doAMode_R(p, hregX86_EAX(), i->Xin.FpCmp.dst); +//.. goto done; +//.. +//.. case Xin_SseConst: { +//.. UShort con = i->Xin.SseConst.con; +//.. p = push_word_from_tags(p, (con >> 12) & 0xF); +//.. p = push_word_from_tags(p, (con >> 8) & 0xF); +//.. p = push_word_from_tags(p, (con >> 4) & 0xF); +//.. p = push_word_from_tags(p, con & 0xF); +//.. /* movl (%esp), %xmm-dst */ +//.. *p++ = 0x0F; +//.. *p++ = 0x10; +//.. *p++ = 0x04 + 8 * (7 & vregNo(i->Xin.SseConst.dst)); +//.. *p++ = 0x24; +//.. /* addl $16, %esp */ +//.. *p++ = 0x83; +//.. *p++ = 0xC4; +//.. *p++ = 0x10; +//.. goto done; +//.. } +//.. +//.. case Xin_SseLdSt: +//.. *p++ = 0x0F; +//.. *p++ = i->Xin.SseLdSt.isLoad ? 0x10 : 0x11; +//.. p = doAMode_M(p, fake(vregNo(i->Xin.SseLdSt.reg)), i->Xin.SseLdSt.addr); +//.. goto done; +//.. +//.. case Xin_SseLdzLO: +//.. vassert(i->Xin.SseLdzLO.sz == 4 || i->Xin.SseLdzLO.sz == 8); +//.. /* movs[sd] amode, %xmm-dst */ +//.. *p++ = i->Xin.SseLdzLO.sz==4 ? 0xF3 : 0xF2; +//.. *p++ = 0x0F; +//.. *p++ = 0x10; +//.. p = doAMode_M(p, fake(vregNo(i->Xin.SseLdzLO.reg)), +//.. i->Xin.SseLdzLO.addr); +//.. goto done; +//.. +//.. case Xin_Sse32Fx4: +//.. xtra = 0; +//.. *p++ = 0x0F; +//.. switch (i->Xin.Sse32Fx4.op) { +//.. case Xsse_ADDF: *p++ = 0x58; break; +//.. case Xsse_DIVF: *p++ = 0x5E; break; +//.. case Xsse_MAXF: *p++ = 0x5F; break; +//.. case Xsse_MINF: *p++ = 0x5D; break; +//.. case Xsse_MULF: *p++ = 0x59; break; +//.. case Xsse_RCPF: *p++ = 0x53; break; +//.. case Xsse_RSQRTF: *p++ = 0x52; break; +//.. case Xsse_SQRTF: *p++ = 0x51; break; +//.. case Xsse_SUBF: *p++ = 0x5C; break; +//.. case Xsse_CMPEQF: *p++ = 0xC2; xtra = 0x100; break; +//.. case Xsse_CMPLTF: *p++ = 0xC2; xtra = 0x101; break; +//.. case Xsse_CMPLEF: *p++ = 0xC2; xtra = 0x102; break; +//.. default: goto bad; +//.. } +//.. p = doAMode_R(p, fake(vregNo(i->Xin.Sse32Fx4.dst)), +//.. fake(vregNo(i->Xin.Sse32Fx4.src)) ); +//.. if (xtra & 0x100) +//.. *p++ = (UChar)(xtra & 0xFF); +//.. goto done; +//.. +//.. case Xin_Sse64Fx2: +//.. xtra = 0; +//.. *p++ = 0x66; +//.. *p++ = 0x0F; +//.. switch (i->Xin.Sse64Fx2.op) { +//.. case Xsse_ADDF: *p++ = 0x58; break; +//.. case Xsse_DIVF: *p++ = 0x5E; break; +//.. case Xsse_MAXF: *p++ = 0x5F; break; +//.. case Xsse_MINF: *p++ = 0x5D; break; +//.. case Xsse_MULF: *p++ = 0x59; break; +//.. case Xsse_RCPF: *p++ = 0x53; break; +//.. case Xsse_RSQRTF: *p++ = 0x52; break; +//.. case Xsse_SQRTF: *p++ = 0x51; break; +//.. case Xsse_SUBF: *p++ = 0x5C; break; +//.. case Xsse_CMPEQF: *p++ = 0xC2; xtra = 0x100; break; +//.. case Xsse_CMPLTF: *p++ = 0xC2; xtra = 0x101; break; +//.. case Xsse_CMPLEF: *p++ = 0xC2; xtra = 0x102; break; +//.. default: goto bad; +//.. } +//.. p = doAMode_R(p, fake(vregNo(i->Xin.Sse64Fx2.dst)), +//.. fake(vregNo(i->Xin.Sse64Fx2.src)) ); +//.. if (xtra & 0x100) +//.. *p++ = (UChar)(xtra & 0xFF); +//.. goto done; +//.. +//.. case Xin_Sse32FLo: +//.. xtra = 0; +//.. *p++ = 0xF3; +//.. *p++ = 0x0F; +//.. switch (i->Xin.Sse32FLo.op) { +//.. case Xsse_ADDF: *p++ = 0x58; break; +//.. case Xsse_DIVF: *p++ = 0x5E; break; +//.. case Xsse_MAXF: *p++ = 0x5F; break; +//.. case Xsse_MINF: *p++ = 0x5D; break; +//.. case Xsse_MULF: *p++ = 0x59; break; +//.. case Xsse_RCPF: *p++ = 0x53; break; +//.. case Xsse_RSQRTF: *p++ = 0x52; break; +//.. case Xsse_SQRTF: *p++ = 0x51; break; +//.. case Xsse_SUBF: *p++ = 0x5C; break; +//.. case Xsse_CMPEQF: *p++ = 0xC2; xtra = 0x100; break; +//.. case Xsse_CMPLTF: *p++ = 0xC2; xtra = 0x101; break; +//.. case Xsse_CMPLEF: *p++ = 0xC2; xtra = 0x102; break; +//.. default: goto bad; +//.. } +//.. p = doAMode_R(p, fake(vregNo(i->Xin.Sse32FLo.dst)), +//.. fake(vregNo(i->Xin.Sse32FLo.src)) ); +//.. if (xtra & 0x100) +//.. *p++ = (UChar)(xtra & 0xFF); +//.. goto done; +//.. +//.. case Xin_Sse64FLo: +//.. xtra = 0; +//.. *p++ = 0xF2; +//.. *p++ = 0x0F; +//.. switch (i->Xin.Sse64FLo.op) { +//.. case Xsse_ADDF: *p++ = 0x58; break; +//.. case Xsse_DIVF: *p++ = 0x5E; break; +//.. case Xsse_MAXF: *p++ = 0x5F; break; +//.. case Xsse_MINF: *p++ = 0x5D; break; +//.. case Xsse_MULF: *p++ = 0x59; break; +//.. case Xsse_RCPF: *p++ = 0x53; break; +//.. case Xsse_RSQRTF: *p++ = 0x52; break; +//.. case Xsse_SQRTF: *p++ = 0x51; break; +//.. case Xsse_SUBF: *p++ = 0x5C; break; +//.. case Xsse_CMPEQF: *p++ = 0xC2; xtra = 0x100; break; +//.. case Xsse_CMPLTF: *p++ = 0xC2; xtra = 0x101; break; +//.. case Xsse_CMPLEF: *p++ = 0xC2; xtra = 0x102; break; +//.. default: goto bad; +//.. } +//.. p = doAMode_R(p, fake(vregNo(i->Xin.Sse64FLo.dst)), +//.. fake(vregNo(i->Xin.Sse64FLo.src)) ); +//.. if (xtra & 0x100) +//.. *p++ = (UChar)(xtra & 0xFF); +//.. goto done; +//.. +//.. case Xin_SseReRg: +//.. # define XX(_n) *p++ = (_n) +//.. switch (i->Xin.SseReRg.op) { +//.. case Xsse_MOV: /*movups*/ XX(0x0F); XX(0x10); break; +//.. case Xsse_OR: XX(0x0F); XX(0x56); break; +//.. case Xsse_XOR: XX(0x0F); XX(0x57); break; +//.. case Xsse_AND: XX(0x0F); XX(0x54); break; +//.. case Xsse_PACKSSD: XX(0x66); XX(0x0F); XX(0x6B); break; +//.. case Xsse_PACKSSW: XX(0x66); XX(0x0F); XX(0x63); break; +//.. case Xsse_PACKUSW: XX(0x66); XX(0x0F); XX(0x67); break; +//.. case Xsse_ADD8: XX(0x66); XX(0x0F); XX(0xFC); break; +//.. case Xsse_ADD16: XX(0x66); XX(0x0F); XX(0xFD); break; +//.. case Xsse_ADD32: XX(0x66); XX(0x0F); XX(0xFE); break; +//.. case Xsse_ADD64: XX(0x66); XX(0x0F); XX(0xD4); break; +//.. case Xsse_QADD8S: XX(0x66); XX(0x0F); XX(0xEC); break; +//.. case Xsse_QADD16S: XX(0x66); XX(0x0F); XX(0xED); break; +//.. case Xsse_QADD8U: XX(0x66); XX(0x0F); XX(0xDC); break; +//.. case Xsse_QADD16U: XX(0x66); XX(0x0F); XX(0xDD); break; +//.. case Xsse_AVG8U: XX(0x66); XX(0x0F); XX(0xE0); break; +//.. case Xsse_AVG16U: XX(0x66); XX(0x0F); XX(0xE3); break; +//.. case Xsse_CMPEQ8: XX(0x66); XX(0x0F); XX(0x74); break; +//.. case Xsse_CMPEQ16: XX(0x66); XX(0x0F); XX(0x75); break; +//.. case Xsse_CMPEQ32: XX(0x66); XX(0x0F); XX(0x76); break; +//.. case Xsse_CMPGT8S: XX(0x66); XX(0x0F); XX(0x64); break; +//.. case Xsse_CMPGT16S: XX(0x66); XX(0x0F); XX(0x65); break; +//.. case Xsse_CMPGT32S: XX(0x66); XX(0x0F); XX(0x66); break; +//.. case Xsse_MAX16S: XX(0x66); XX(0x0F); XX(0xEE); break; +//.. case Xsse_MAX8U: XX(0x66); XX(0x0F); XX(0xDE); break; +//.. case Xsse_MIN16S: XX(0x66); XX(0x0F); XX(0xEA); break; +//.. case Xsse_MIN8U: XX(0x66); XX(0x0F); XX(0xDA); break; +//.. case Xsse_MULHI16U: XX(0x66); XX(0x0F); XX(0xE4); break; +//.. case Xsse_MULHI16S: XX(0x66); XX(0x0F); XX(0xE5); break; +//.. case Xsse_MUL16: XX(0x66); XX(0x0F); XX(0xD5); break; +//.. case Xsse_SHL16: XX(0x66); XX(0x0F); XX(0xF1); break; +//.. case Xsse_SHL32: XX(0x66); XX(0x0F); XX(0xF2); break; +//.. case Xsse_SHL64: XX(0x66); XX(0x0F); XX(0xF3); break; +//.. case Xsse_SAR16: XX(0x66); XX(0x0F); XX(0xE1); break; +//.. case Xsse_SAR32: XX(0x66); XX(0x0F); XX(0xE2); break; +//.. case Xsse_SHR16: XX(0x66); XX(0x0F); XX(0xD1); break; +//.. case Xsse_SHR32: XX(0x66); XX(0x0F); XX(0xD2); break; +//.. case Xsse_SHR64: XX(0x66); XX(0x0F); XX(0xD3); break; +//.. case Xsse_SUB8: XX(0x66); XX(0x0F); XX(0xF8); break; +//.. case Xsse_SUB16: XX(0x66); XX(0x0F); XX(0xF9); break; +//.. case Xsse_SUB32: XX(0x66); XX(0x0F); XX(0xFA); break; +//.. case Xsse_SUB64: XX(0x66); XX(0x0F); XX(0xFB); break; +//.. case Xsse_QSUB8S: XX(0x66); XX(0x0F); XX(0xE8); break; +//.. case Xsse_QSUB16S: XX(0x66); XX(0x0F); XX(0xE9); break; +//.. case Xsse_QSUB8U: XX(0x66); XX(0x0F); XX(0xD8); break; +//.. case Xsse_QSUB16U: XX(0x66); XX(0x0F); XX(0xD9); break; +//.. case Xsse_UNPCKHB: XX(0x66); XX(0x0F); XX(0x68); break; +//.. case Xsse_UNPCKHW: XX(0x66); XX(0x0F); XX(0x69); break; +//.. case Xsse_UNPCKHD: XX(0x66); XX(0x0F); XX(0x6A); break; +//.. case Xsse_UNPCKHQ: XX(0x66); XX(0x0F); XX(0x6D); break; +//.. case Xsse_UNPCKLB: XX(0x66); XX(0x0F); XX(0x60); break; +//.. case Xsse_UNPCKLW: XX(0x66); XX(0x0F); XX(0x61); break; +//.. case Xsse_UNPCKLD: XX(0x66); XX(0x0F); XX(0x62); break; +//.. case Xsse_UNPCKLQ: XX(0x66); XX(0x0F); XX(0x6C); break; +//.. default: goto bad; +//.. } +//.. p = doAMode_R(p, fake(vregNo(i->Xin.SseReRg.dst)), +//.. fake(vregNo(i->Xin.SseReRg.src)) ); +//.. # undef XX +//.. goto done; +//.. +//.. case Xin_SseCMov: +//.. /* jmp fwds if !condition */ +//.. *p++ = 0x70 + (i->Xin.SseCMov.cond ^ 1); +//.. *p++ = 0; /* # of bytes in the next bit, which we don't know yet */ +//.. ptmp = p; +//.. +//.. /* movaps %src, %dst */ +//.. *p++ = 0x0F; +//.. *p++ = 0x28; +//.. p = doAMode_R(p, fake(vregNo(i->Xin.SseCMov.dst)), +//.. fake(vregNo(i->Xin.SseCMov.src)) ); +//.. +//.. /* Fill in the jump offset. */ +//.. *(ptmp-1) = p - ptmp; +//.. goto done; +//.. +//.. case Xin_SseShuf: +//.. *p++ = 0x66; +//.. *p++ = 0x0F; +//.. *p++ = 0x70; +//.. p = doAMode_R(p, fake(vregNo(i->Xin.SseShuf.dst)), +//.. fake(vregNo(i->Xin.SseShuf.src)) ); +//.. *p++ = (UChar)(i->Xin.SseShuf.order); +//.. goto done; + + default: + goto bad; + } + + bad: + ppPPC32Instr(i); + vpanic("emit_PPC32Instr"); + /*NOTREACHED*/ + + goto done; // CAB: Rem to remove - Just reducing compiler warnings. + done: + vassert(p - &buf[0] <= 32); + return p - &buf[0]; + +# undef fake +} + +/*---------------------------------------------------------------*/ +/*--- end host-ppc32/hdefs.c ---*/ +/*---------------------------------------------------------------*/ diff --git a/VEX/priv/host-ppc32/hdefs.h b/VEX/priv/host-ppc32/hdefs.h new file mode 100644 index 0000000000..a1b879df25 --- /dev/null +++ b/VEX/priv/host-ppc32/hdefs.h @@ -0,0 +1,720 @@ + +/*---------------------------------------------------------------*/ +/*--- ---*/ +/*--- This file (host-ppc32/hdefs.h) is ---*/ +/*--- Copyright (c) 2005 OpenWorks LLP. All rights reserved. ---*/ +/*--- ---*/ +/*---------------------------------------------------------------*/ + +/* + This file is part of LibVEX, a library for dynamic binary + instrumentation and translation. + + Copyright (C) 2004-2005 OpenWorks, LLP. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; Version 2 dated June 1991 of the + license. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or liability + for damages. See the GNU General Public License for more details. + + Neither the names of the U.S. Department of Energy nor the + University of California nor the names of its contributors may be + used to endorse or promote products derived from this software + without prior written permission. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +*/ + +#ifndef __LIBVEX_HOST_PPC32_HDEFS_H +#define __LIBVEX_HOST_PPC32_HDEFS_H + + +/* --------- Registers. --------- */ + +/* The usual HReg abstraction. There are 32 real int regs, + 32 real float regs, and 0 real vector regs. +*/ + +extern void ppHRegPPC32 ( HReg ); + +extern HReg hregPPC32_GPR0 ( void ); +extern HReg hregPPC32_GPR1 ( void ); +extern HReg hregPPC32_GPR2 ( void ); +extern HReg hregPPC32_GPR3 ( void ); +extern HReg hregPPC32_GPR4 ( void ); +extern HReg hregPPC32_GPR5 ( void ); +extern HReg hregPPC32_GPR6 ( void ); +extern HReg hregPPC32_GPR7 ( void ); +extern HReg hregPPC32_GPR8 ( void ); +extern HReg hregPPC32_GPR9 ( void ); +extern HReg hregPPC32_GPR10 ( void ); +extern HReg hregPPC32_GPR11 ( void ); +extern HReg hregPPC32_GPR12 ( void ); +extern HReg hregPPC32_GPR13 ( void ); +extern HReg hregPPC32_GPR14 ( void ); +extern HReg hregPPC32_GPR15 ( void ); +extern HReg hregPPC32_GPR16 ( void ); +extern HReg hregPPC32_GPR17 ( void ); +extern HReg hregPPC32_GPR18 ( void ); +extern HReg hregPPC32_GPR19 ( void ); +extern HReg hregPPC32_GPR20 ( void ); +extern HReg hregPPC32_GPR21 ( void ); +extern HReg hregPPC32_GPR22 ( void ); +extern HReg hregPPC32_GPR23 ( void ); +extern HReg hregPPC32_GPR24 ( void ); +extern HReg hregPPC32_GPR25 ( void ); +extern HReg hregPPC32_GPR26 ( void ); +extern HReg hregPPC32_GPR27 ( void ); +extern HReg hregPPC32_GPR28 ( void ); +extern HReg hregPPC32_GPR29 ( void ); +extern HReg hregPPC32_GPR30 ( void ); +extern HReg hregPPC32_GPR31 ( void ); + +extern HReg hregPPC32_FPR0 ( void ); +extern HReg hregPPC32_FPR1 ( void ); +extern HReg hregPPC32_FPR2 ( void ); +extern HReg hregPPC32_FPR3 ( void ); +extern HReg hregPPC32_FPR4 ( void ); +extern HReg hregPPC32_FPR5 ( void ); +extern HReg hregPPC32_FPR6 ( void ); +extern HReg hregPPC32_FPR7 ( void ); +extern HReg hregPPC32_FPR8 ( void ); +extern HReg hregPPC32_FPR9 ( void ); +extern HReg hregPPC32_FPR10 ( void ); +extern HReg hregPPC32_FPR11 ( void ); +extern HReg hregPPC32_FPR12 ( void ); +extern HReg hregPPC32_FPR13 ( void ); +extern HReg hregPPC32_FPR14 ( void ); +extern HReg hregPPC32_FPR15 ( void ); +extern HReg hregPPC32_FPR16 ( void ); +extern HReg hregPPC32_FPR17 ( void ); +extern HReg hregPPC32_FPR18 ( void ); +extern HReg hregPPC32_FPR19 ( void ); +extern HReg hregPPC32_FPR20 ( void ); +extern HReg hregPPC32_FPR21 ( void ); +extern HReg hregPPC32_FPR22 ( void ); +extern HReg hregPPC32_FPR23 ( void ); +extern HReg hregPPC32_FPR24 ( void ); +extern HReg hregPPC32_FPR25 ( void ); +extern HReg hregPPC32_FPR26 ( void ); +extern HReg hregPPC32_FPR27 ( void ); +extern HReg hregPPC32_FPR28 ( void ); +extern HReg hregPPC32_FPR29 ( void ); +extern HReg hregPPC32_FPR30 ( void ); +extern HReg hregPPC32_FPR31 ( void ); + + + +//.. /* --------- Condition codes, Intel encoding. --------- */ +//.. +//.. typedef +//.. enum { +//.. Xcc_O = 0, /* overflow */ +//.. Xcc_NO = 1, /* no overflow */ +//.. +//.. Xcc_B = 2, /* below */ +//.. Xcc_NB = 3, /* not below */ +//.. +//.. Xcc_Z = 4, /* zero */ +//.. Xcc_NZ = 5, /* not zero */ +//.. +//.. Xcc_BE = 6, /* below or equal */ +//.. Xcc_NBE = 7, /* not below or equal */ +//.. +//.. Xcc_S = 8, /* negative */ +//.. Xcc_NS = 9, /* not negative */ +//.. +//.. Xcc_P = 10, /* parity even */ +//.. Xcc_NP = 11, /* not parity even */ +//.. +//.. Xcc_L = 12, /* jump less */ +//.. Xcc_NL = 13, /* not less */ +//.. +//.. Xcc_LE = 14, /* less or equal */ +//.. Xcc_NLE = 15, /* not less or equal */ +//.. +//.. Xcc_ALWAYS = 16 /* the usual hack */ +//.. } +//.. X86CondCode; +//.. +//.. extern HChar* showX86CondCode ( X86CondCode ); + + +/* --------- Memory address expressions (amodes). --------- */ + +typedef + enum { + Pam_IR, /* Immediate + Reg */ + Pam_RR /* Reg1 + Reg2 */ + } + PPC32AModeTag; + +typedef + struct { + PPC32AModeTag tag; + union { + struct { + HReg base; + UInt index; + } IR; + struct { + HReg base; + HReg index; + } RR; + } Pam; + } + PPC32AMode; + +extern PPC32AMode* PPC32AMode_IR ( UInt, HReg ); +extern PPC32AMode* PPC32AMode_RR ( HReg, HReg ); + +extern PPC32AMode* dopyPPC32AMode ( PPC32AMode* ); + +extern void ppPPC32AMode ( PPC32AMode* ); + + +/* --------- Operand, which can be reg, immediate or memory. --------- */ + +typedef + enum { + Prmi_Imm, + Prmi_Reg, + Prmi_Mem + } + PPC32RMITag; + +typedef + struct { + PPC32RMITag tag; + union { + struct { + UInt imm32; + } Imm; + struct { + HReg reg; + } Reg; + struct { + PPC32AMode* am; + } Mem; + } + Prmi; + } + PPC32RMI; + +extern PPC32RMI* PPC32RMI_Imm ( UInt ); +extern PPC32RMI* PPC32RMI_Reg ( HReg ); +extern PPC32RMI* PPC32RMI_Mem ( PPC32AMode* ); + +extern void ppPPC32RMI ( PPC32RMI* ); + + +/* --------- Operand, which can be reg or immediate only. --------- */ + +typedef + enum { + Pri_Imm, + Pri_Reg + } + PPC32RITag; + +typedef + struct { + PPC32RITag tag; + union { + struct { + UInt imm32; + } Imm; + struct { + HReg reg; + } Reg; + } + Pri; + } + PPC32RI; + +extern PPC32RI* PPC32RI_Imm ( UInt ); +extern PPC32RI* PPC32RI_Reg ( HReg ); + +extern void ppPPC32RI ( PPC32RI* ); + + +/* --------- Operand, which can be reg or memory only. --------- */ + +typedef + enum { + Prm_Reg, + Prm_Mem + } + PPC32RMTag; + +typedef + struct { + PPC32RMTag tag; + union { + struct { + HReg reg; + } Reg; + struct { + PPC32AMode* am; + } Mem; + } + Prm; + } + PPC32RM; + +extern PPC32RM* PPC32RM_Reg ( HReg ); +extern PPC32RM* PPC32RM_Mem ( PPC32AMode* ); + +extern void ppPPC32RM ( PPC32RM* ); + + +//.. /* --------- Instructions. --------- */ +//.. +//.. /* --------- */ +//.. typedef +//.. enum { +//.. Xss_16, +//.. Xss_32 +//.. } +//.. X86ScalarSz; +//.. +//.. extern HChar* showX86ScalarSz ( X86ScalarSz ); +//.. +//.. +//.. /* --------- */ +//.. typedef +//.. enum { +//.. Xun_NEG, +//.. Xun_NOT +//.. } +//.. X86UnaryOp; +//.. +//.. extern HChar* showX86UnaryOp ( X86UnaryOp ); +//.. +//.. +//.. /* --------- */ +//.. typedef +//.. enum { +//.. Xalu_INVALID, +//.. Xalu_MOV, +//.. Xalu_CMP, +//.. Xalu_ADD, Xalu_SUB, Xalu_ADC, Xalu_SBB, +//.. Xalu_AND, Xalu_OR, Xalu_XOR, +//.. Xalu_MUL +//.. } +//.. X86AluOp; +//.. +//.. extern HChar* showX86AluOp ( X86AluOp ); +//.. +//.. +//.. /* --------- */ +//.. typedef +//.. enum { +//.. Xsh_INVALID, +//.. Xsh_SHL, Xsh_SHR, Xsh_SAR, +//.. Xsh_ROL, Xsh_ROR +//.. } +//.. X86ShiftOp; +//.. +//.. extern HChar* showX86ShiftOp ( X86ShiftOp ); +//.. +//.. +//.. /* --------- */ +//.. typedef +//.. enum { +//.. Xfp_INVALID, +//.. /* Binary */ +//.. Xfp_ADD, Xfp_SUB, Xfp_MUL, Xfp_DIV, +//.. Xfp_SCALE, Xfp_ATAN, Xfp_YL2X, Xfp_YL2XP1, Xfp_PREM, Xfp_PREM1, +//.. /* Unary */ +//.. Xfp_SQRT, Xfp_ABS, Xfp_NEG, Xfp_MOV, Xfp_SIN, Xfp_COS, Xfp_TAN, +//.. Xfp_ROUND, Xfp_2XM1 +//.. } +//.. X86FpOp; +//.. +//.. extern HChar* showX86FpOp ( X86FpOp ); +//.. +//.. +//.. /* --------- */ +//.. typedef +//.. enum { +//.. Xsse_INVALID, +//.. /* mov */ +//.. Xsse_MOV, +//.. /* Floating point binary */ +//.. Xsse_ADDF, Xsse_SUBF, Xsse_MULF, Xsse_DIVF, +//.. Xsse_MAXF, Xsse_MINF, +//.. Xsse_CMPEQF, Xsse_CMPLTF, Xsse_CMPLEF, Xsse_CMPUNF, +//.. /* Floating point unary */ +//.. Xsse_RCPF, Xsse_RSQRTF, Xsse_SQRTF, +//.. /* Bitwise */ +//.. Xsse_AND, Xsse_OR, Xsse_XOR, Xsse_ANDN, +//.. /* Integer binary */ +//.. Xsse_ADD8, Xsse_ADD16, Xsse_ADD32, Xsse_ADD64, +//.. Xsse_QADD8U, Xsse_QADD16U, +//.. Xsse_QADD8S, Xsse_QADD16S, +//.. Xsse_SUB8, Xsse_SUB16, Xsse_SUB32, Xsse_SUB64, +//.. Xsse_QSUB8U, Xsse_QSUB16U, +//.. Xsse_QSUB8S, Xsse_QSUB16S, +//.. Xsse_MUL16, +//.. Xsse_MULHI16U, +//.. Xsse_MULHI16S, +//.. Xsse_AVG8U, Xsse_AVG16U, +//.. Xsse_MAX16S, +//.. Xsse_MAX8U, +//.. Xsse_MIN16S, +//.. Xsse_MIN8U, +//.. Xsse_CMPEQ8, Xsse_CMPEQ16, Xsse_CMPEQ32, +//.. Xsse_CMPGT8S, Xsse_CMPGT16S, Xsse_CMPGT32S, +//.. Xsse_SHL16, Xsse_SHL32, Xsse_SHL64, +//.. Xsse_SHR16, Xsse_SHR32, Xsse_SHR64, +//.. Xsse_SAR16, Xsse_SAR32, +//.. Xsse_PACKSSD, Xsse_PACKSSW, Xsse_PACKUSW, +//.. Xsse_UNPCKHB, Xsse_UNPCKHW, Xsse_UNPCKHD, Xsse_UNPCKHQ, +//.. Xsse_UNPCKLB, Xsse_UNPCKLW, Xsse_UNPCKLD, Xsse_UNPCKLQ +//.. } +//.. X86SseOp; +//.. +//.. extern HChar* showX86SseOp ( X86SseOp ); + + +/* --------- */ +typedef + enum { + Pin_Nada, /* nix */ +//.. Xin_Alu32R, /* 32-bit mov/arith/logical, dst=REG */ +//.. Xin_Alu32M, /* 32-bit mov/arith/logical, dst=MEM */ +//.. Xin_Sh32, /* 32-bit shift/rotate, dst=REG or MEM */ +//.. Xin_Test32, /* 32-bit test (AND, set flags, discard result) */ +//.. Xin_Unary32, /* 32-bit not and neg */ +//.. Xin_MulL, /* widening multiply */ +//.. Xin_Div, /* div and mod */ +//.. Xin_Sh3232, /* shldl or shrdl */ +//.. Xin_Push, /* push (32-bit?) value on stack */ +//.. Xin_Call, /* call to address in register */ +//.. Xin_Goto, /* conditional/unconditional jmp to dst */ +//.. Xin_CMov32, /* conditional move */ +//.. Xin_LoadEX, /* mov{s,z}{b,w}l from mem to reg */ +//.. Xin_Store, /* store 16/8 bit value in memory */ +//.. Xin_Set32, /* convert condition code to 32-bit value */ +//.. Xin_Bsfr32, /* 32-bit bsf/bsr */ +//.. Xin_MFence, /* mem fence (not just sse2, but sse0 and 1 too) */ +//.. +//.. Xin_FpUnary, /* FP fake unary op */ +//.. Xin_FpBinary, /* FP fake binary op */ +//.. Xin_FpLdSt, /* FP fake load/store */ +//.. Xin_FpLdStI, /* FP fake load/store, converting to/from Int */ +//.. Xin_Fp64to32, /* FP round IEEE754 double to IEEE754 single */ +//.. Xin_FpCMov, /* FP fake floating point conditional move */ +//.. Xin_FpLdStCW, /* fldcw / fstcw */ +//.. Xin_FpStSW_AX, /* fstsw %ax */ +//.. Xin_FpCmp, /* FP compare, generating a C320 value into int reg */ +//.. +//.. Xin_SseConst, /* Generate restricted SSE literal */ +//.. Xin_SseLdSt, /* SSE load/store, no alignment constraints */ +//.. Xin_SseLdzLO, /* SSE load low 32/64 bits, zero remainder of reg */ +//.. Xin_Sse32Fx4, /* SSE binary, 32Fx4 */ +//.. Xin_Sse32FLo, /* SSE binary, 32F in lowest lane only */ +//.. Xin_Sse64Fx2, /* SSE binary, 64Fx2 */ +//.. Xin_Sse64FLo, /* SSE binary, 64F in lowest lane only */ +//.. Xin_SseReRg, /* SSE binary general reg-reg, Re, Rg */ +//.. Xin_SseCMov, /* SSE conditional move */ +//.. Xin_SseShuf /* SSE2 shuffle (pshufd) */ + } + PPC32InstrTag; + +/* Destinations are on the RIGHT (second operand) */ + +typedef + struct { + PPC32InstrTag tag; +//.. union { +//.. struct { +//.. X86AluOp op; +//.. X86RMI* src; +//.. HReg dst; +//.. } Alu32R; +//.. struct { +//.. X86AluOp op; +//.. X86RI* src; +//.. X86AMode* dst; +//.. } Alu32M; +//.. struct { +//.. X86ShiftOp op; +//.. UInt src; /* shift amount, or 0 means %cl */ +//.. X86RM* dst; +//.. } Sh32; +//.. struct { +//.. X86RI* src; +//.. X86RM* dst; +//.. } Test32; +//.. /* Not and Neg */ +//.. struct { +//.. X86UnaryOp op; +//.. X86RM* dst; +//.. } Unary32; +//.. /* DX:AX = AX *s/u r/m16, or EDX:EAX = EAX *s/u r/m32 */ +//.. struct { +//.. Bool syned; +//.. X86ScalarSz ssz; +//.. X86RM* src; +//.. } MulL; +//.. /* x86 div/idiv instruction. Modifies EDX and EAX and reads src. */ +//.. struct { +//.. Bool syned; +//.. X86ScalarSz ssz; +//.. X86RM* src; +//.. } Div; +//.. /* shld/shrd. op may only be Xsh_SHL or Xsh_SHR */ +//.. struct { +//.. X86ShiftOp op; +//.. UInt amt; /* shift amount, or 0 means %cl */ +//.. HReg src; +//.. HReg dst; +//.. } Sh3232; +//.. struct { +//.. X86RMI* src; +//.. } Push; +//.. /* Pseudo-insn. Call target (an absolute address), on given +//.. condition (which could be Xcc_ALWAYS). */ +//.. struct { +//.. X86CondCode cond; +//.. Addr32 target; +//.. Int regparms; /* 0 .. 3 */ +//.. } Call; +//.. /* Pseudo-insn. Goto dst, on given condition (which could be +//.. Xcc_ALWAYS). Note importantly that if the jump is +//.. conditional (not Xcc_ALWAYS) the jump kind *must* be +//.. Ijk_Boring. Ie non-Boring conditional jumps are +//.. not allowed. */ +//.. struct { +//.. IRJumpKind jk; +//.. X86CondCode cond; +//.. X86RI* dst; +//.. } Goto; +//.. /* Mov src to dst on the given condition, which may not +//.. be the bogus Xcc_ALWAYS. */ +//.. struct { +//.. X86CondCode cond; +//.. X86RM* src; +//.. HReg dst; +//.. } CMov32; +//.. /* Sign/Zero extending loads. Dst size is always 32 bits. */ +//.. struct { +//.. UChar szSmall; +//.. Bool syned; +//.. X86AMode* src; +//.. HReg dst; +//.. } LoadEX; +//.. /* 16/8 bit stores, which are troublesome (particularly +//.. 8-bit) */ +//.. struct { +//.. UChar sz; /* only 1 or 2 */ +//.. HReg src; +//.. X86AMode* dst; +//.. } Store; +//.. /* Convert a x86 condition code to a 32-bit value (0 or 1). */ +//.. struct { +//.. X86CondCode cond; +//.. HReg dst; +//.. } Set32; +//.. /* 32-bit bsf or bsr. */ +//.. struct { +//.. Bool isFwds; +//.. HReg src; +//.. HReg dst; +//.. } Bsfr32; +//.. /* Mem fence (not just sse2, but sse0 and 1 too). In short, +//.. an insn which flushes all preceding loads and stores as +//.. much as possible before continuing. On SSE2 we emit a +//.. real "mfence", on SSE1 "sfence ; lock addl $0,0(%esp)" and +//.. on SSE0 "lock addl $0,0(%esp)". This insn therefore +//.. carries the subarch so the assembler knows what to +//.. emit. */ +//.. struct { +//.. VexSubArch subarch; +//.. } MFence; +//.. +//.. /* X86 Floating point (fake 3-operand, "flat reg file" insns) */ +//.. struct { +//.. X86FpOp op; +//.. HReg src; +//.. HReg dst; +//.. } FpUnary; +//.. struct { +//.. X86FpOp op; +//.. HReg srcL; +//.. HReg srcR; +//.. HReg dst; +//.. } FpBinary; +//.. struct { +//.. Bool isLoad; +//.. UChar sz; /* only 4 (IEEE single) or 8 (IEEE double) */ +//.. HReg reg; +//.. X86AMode* addr; +//.. } FpLdSt; +//.. /* Move 64-bit float to/from memory, converting to/from +//.. signed int on the way. Note the conversions will observe +//.. the host FPU rounding mode currently in force. */ +//.. struct { +//.. Bool isLoad; +//.. UChar sz; /* only 2, 4 or 8 */ +//.. HReg reg; +//.. X86AMode* addr; +//.. } FpLdStI; +//.. /* By observing the current FPU rounding mode, round (etc) +//.. src into dst given that dst should be interpreted as an +//.. IEEE754 32-bit (float) type. */ +//.. struct { +//.. HReg src; +//.. HReg dst; +//.. } Fp64to32; +//.. /* Mov src to dst on the given condition, which may not +//.. be the bogus Xcc_ALWAYS. */ +//.. struct { +//.. X86CondCode cond; +//.. HReg src; +//.. HReg dst; +//.. } FpCMov; +//.. /* Load/store the FPU's 16-bit control word (fldcw/fstcw) */ +//.. struct { +//.. Bool isLoad; +//.. X86AMode* addr; +//.. } +//.. FpLdStCW; +//.. /* fstsw %ax */ +//.. struct { +//.. /* no fields */ +//.. } +//.. FpStSW_AX; +//.. /* Do a compare, generating the C320 bits into the dst. */ +//.. struct { +//.. HReg srcL; +//.. HReg srcR; +//.. HReg dst; +//.. } FpCmp; +//.. +//.. /* Simplistic SSE[123] */ +//.. struct { +//.. UShort con; +//.. HReg dst; +//.. } SseConst; +//.. struct { +//.. Bool isLoad; +//.. HReg reg; +//.. X86AMode* addr; +//.. } SseLdSt; +//.. struct { +//.. Int sz; /* 4 or 8 only */ +//.. HReg reg; +//.. X86AMode* addr; +//.. } SseLdzLO; +//.. struct { +//.. X86SseOp op; +//.. HReg src; +//.. HReg dst; +//.. } Sse32Fx4; +//.. struct { +//.. X86SseOp op; +//.. HReg src; +//.. HReg dst; +//.. } Sse32FLo; +//.. struct { +//.. X86SseOp op; +//.. HReg src; +//.. HReg dst; +//.. } Sse64Fx2; +//.. struct { +//.. X86SseOp op; +//.. HReg src; +//.. HReg dst; +//.. } Sse64FLo; +//.. struct { +//.. X86SseOp op; +//.. HReg src; +//.. HReg dst; +//.. } SseReRg; +//.. /* Mov src to dst on the given condition, which may not +//.. be the bogus Xcc_ALWAYS. */ +//.. struct { +//.. X86CondCode cond; +//.. HReg src; +//.. HReg dst; +//.. } SseCMov; +//.. struct { +//.. Int order; /* 0 <= order <= 0xFF */ +//.. HReg src; +//.. HReg dst; +//.. } SseShuf; +//.. +//.. } Xin; + } + PPC32Instr; + +//.. extern X86Instr* X86Instr_Alu32R ( X86AluOp, X86RMI*, HReg ); +//.. extern X86Instr* X86Instr_Alu32M ( X86AluOp, X86RI*, X86AMode* ); +//.. extern X86Instr* X86Instr_Unary32 ( X86UnaryOp op, X86RM* dst ); +//.. extern X86Instr* X86Instr_Sh32 ( X86ShiftOp, UInt, X86RM* ); +//.. extern X86Instr* X86Instr_Test32 ( X86RI* src, X86RM* dst ); +//.. extern X86Instr* X86Instr_MulL ( Bool syned, X86ScalarSz, X86RM* ); +//.. extern X86Instr* X86Instr_Div ( Bool syned, X86ScalarSz, X86RM* ); +//.. extern X86Instr* X86Instr_Sh3232 ( X86ShiftOp, UInt amt, HReg src, HReg dst ); +//.. extern X86Instr* X86Instr_Push ( X86RMI* ); +//.. extern X86Instr* X86Instr_Call ( X86CondCode, Addr32, Int ); +//.. extern X86Instr* X86Instr_Goto ( IRJumpKind, X86CondCode cond, X86RI* dst ); +//.. extern X86Instr* X86Instr_CMov32 ( X86CondCode, X86RM* src, HReg dst ); +//.. extern X86Instr* X86Instr_LoadEX ( UChar szSmall, Bool syned, +//.. X86AMode* src, HReg dst ); +//.. extern X86Instr* X86Instr_Store ( UChar sz, HReg src, X86AMode* dst ); +//.. extern X86Instr* X86Instr_Set32 ( X86CondCode cond, HReg dst ); +//.. extern X86Instr* X86Instr_Bsfr32 ( Bool isFwds, HReg src, HReg dst ); +//.. extern X86Instr* X86Instr_MFence ( VexSubArch ); +//.. +//.. extern X86Instr* X86Instr_FpUnary ( X86FpOp op, HReg src, HReg dst ); +//.. extern X86Instr* X86Instr_FpBinary ( X86FpOp op, HReg srcL, HReg srcR, HReg dst ); +//.. extern X86Instr* X86Instr_FpLdSt ( Bool isLoad, UChar sz, HReg reg, X86AMode* ); +//.. extern X86Instr* X86Instr_FpLdStI ( Bool isLoad, UChar sz, HReg reg, X86AMode* ); +//.. extern X86Instr* X86Instr_Fp64to32 ( HReg src, HReg dst ); +//.. extern X86Instr* X86Instr_FpCMov ( X86CondCode, HReg src, HReg dst ); +//.. extern X86Instr* X86Instr_FpLdStCW ( Bool isLoad, X86AMode* ); +//.. extern X86Instr* X86Instr_FpStSW_AX ( void ); +//.. extern X86Instr* X86Instr_FpCmp ( HReg srcL, HReg srcR, HReg dst ); +//.. +//.. extern X86Instr* X86Instr_SseConst ( UShort con, HReg dst ); +//.. extern X86Instr* X86Instr_SseLdSt ( Bool isLoad, HReg, X86AMode* ); +//.. extern X86Instr* X86Instr_SseLdzLO ( Int sz, HReg, X86AMode* ); +//.. extern X86Instr* X86Instr_Sse32Fx4 ( X86SseOp, HReg, HReg ); +//.. extern X86Instr* X86Instr_Sse32FLo ( X86SseOp, HReg, HReg ); +//.. extern X86Instr* X86Instr_Sse64Fx2 ( X86SseOp, HReg, HReg ); +//.. extern X86Instr* X86Instr_Sse64FLo ( X86SseOp, HReg, HReg ); +//.. extern X86Instr* X86Instr_SseReRg ( X86SseOp, HReg, HReg ); +//.. extern X86Instr* X86Instr_SseCMov ( X86CondCode, HReg src, HReg dst ); +//.. extern X86Instr* X86Instr_SseShuf ( Int order, HReg src, HReg dst ); + + +extern void ppPPC32Instr ( PPC32Instr* ); + +/* Some functions that insulate the register allocator from details + of the underlying instruction set. */ +extern void getRegUsage_PPC32Instr ( HRegUsage*, PPC32Instr* ); +extern void mapRegs_PPC32Instr ( HRegRemap*, PPC32Instr* ); +extern Bool isMove_PPC32Instr ( PPC32Instr*, HReg*, HReg* ); +extern Int emit_PPC32Instr ( UChar* buf, Int nbuf, PPC32Instr* ); +extern PPC32Instr* genSpill_PPC32 ( HReg rreg, Int offset ); +extern PPC32Instr* genReload_PPC32 ( HReg rreg, Int offset ); +extern void getAllocableRegs_PPC32 ( Int*, HReg** ); +extern HInstrArray* iselBB_PPC32 ( IRBB*, VexSubArch ); + +#endif /* ndef __LIBVEX_HOST_PPC32_HDEFS_H */ + +/*---------------------------------------------------------------*/ +/*--- end host-ppc32/hdefs.h ---*/ +/*---------------------------------------------------------------*/ diff --git a/VEX/priv/host-ppc32/isel.c b/VEX/priv/host-ppc32/isel.c new file mode 100644 index 0000000000..30c6d36087 --- /dev/null +++ b/VEX/priv/host-ppc32/isel.c @@ -0,0 +1,3474 @@ + +/*---------------------------------------------------------------*/ +/*--- ---*/ +/*--- This file (host-ppc32/isel.c) is ---*/ +/*--- Copyright (c) 2005 OpenWorks LLP. All rights reserved. ---*/ +/*--- ---*/ +/*---------------------------------------------------------------*/ + +/* + This file is part of LibVEX, a library for dynamic binary + instrumentation and translation. + + Copyright (C) 2004-2005 OpenWorks, LLP. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; Version 2 dated June 1991 of the + license. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or liability + for damages. See the GNU General Public License for more details. + + Neither the names of the U.S. Department of Energy nor the + University of California nor the names of its contributors may be + used to endorse or promote products derived from this software + without prior written permission. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +*/ + +#include "libvex_basictypes.h" +#include "libvex_ir.h" +#include "libvex.h" + +//.. #include "ir/irmatch.h" +#include "main/vex_util.h" +#include "main/vex_globals.h" +#include "host-generic/h_generic_regs.h" +//.. #include "host-generic/h_generic_simd64.h" +#include "host-ppc32/hdefs.h" +//.. +//.. +//.. /*---------------------------------------------------------*/ +//.. /*--- x87 control word stuff ---*/ +//.. /*---------------------------------------------------------*/ +//.. +//.. /* Vex-generated code expects to run with the FPU set as follows: all +//.. exceptions masked, round-to-nearest, precision = 53 bits. This +//.. corresponds to a FPU control word value of 0x027F. +//.. +//.. Similarly the SSE control word (%mxcsr) should be 0x1F80. +//.. +//.. %fpucw and %mxcsr should have these values on entry to +//.. Vex-generated code, and should those values should be +//.. unchanged at exit. +//.. */ +//.. +//.. #define DEFAULT_FPUCW 0x027F +//.. +//.. /* debugging only, do not use */ +//.. /* define DEFAULT_FPUCW 0x037F */ +//.. +//.. +//.. /*---------------------------------------------------------*/ +//.. /*--- misc helpers ---*/ +//.. /*---------------------------------------------------------*/ +//.. +//.. /* These are duplicated in guest-x86/toIR.c */ +//.. static IRExpr* unop ( IROp op, IRExpr* a ) +//.. { +//.. return IRExpr_Unop(op, a); +//.. } +//.. +//.. static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 ) +//.. { +//.. return IRExpr_Binop(op, a1, a2); +//.. } +//.. +//.. static IRExpr* mkU64 ( ULong i ) +//.. { +//.. return IRExpr_Const(IRConst_U64(i)); +//.. } +//.. +//.. static IRExpr* mkU32 ( UInt i ) +//.. { +//.. return IRExpr_Const(IRConst_U32(i)); +//.. } +//.. +//.. static IRExpr* bind ( Int binder ) +//.. { +//.. return IRExpr_Binder(binder); +//.. } + +/*---------------------------------------------------------*/ +/*--- 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(s) are 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. + + - vregmap holds the primary register for the IRTemp. + - vregmapHI is only used for 64-bit integer-typed + IRTemps. It holds the identity of a second + 32-bit virtual HReg, which holds the high half + of the value. + + - The code array, that is, the insns selected so far. + + - A counter, for generating new virtual registers. + + - The host subarchitecture we are selecting insns for. + This is set at the start and does not change. + + Note, this is all host-independent. (JRS 20050201: well, kinda + ... not completely. Compare with ISelEnv for amd64.) +*/ + +typedef + struct { + IRTypeEnv* type_env; + + HReg* vregmap; + HReg* vregmapHI; + Int n_vregmap; + + HInstrArray* code; + + Int vreg_ctr; + + VexSubArch subarch; + } + ISelEnv; + + +#if 0 +static HReg lookupIRTemp ( ISelEnv* env, IRTemp tmp ) +{ + vassert(tmp >= 0); + vassert(tmp < env->n_vregmap); + return env->vregmap[tmp]; +} +#endif + +//.. static void lookupIRTemp64 ( HReg* vrHI, HReg* vrLO, ISelEnv* env, IRTemp tmp ) +//.. { +//.. vassert(tmp >= 0); +//.. vassert(tmp < env->n_vregmap); +//.. vassert(env->vregmapHI[tmp] != INVALID_HREG); +//.. *vrLO = env->vregmap[tmp]; +//.. *vrHI = env->vregmapHI[tmp]; +//.. } +//.. +//.. static void addInstr ( ISelEnv* env, X86Instr* instr ) +//.. { +//.. addHInstr(env->code, instr); +//.. if (vex_traceflags & VEX_TRACE_VCODE) { +//.. ppX86Instr(instr); +//.. vex_printf("\n"); +//.. } +//.. } +//.. +//.. static HReg newVRegI ( ISelEnv* env ) +//.. { +//.. HReg reg = mkHReg(env->vreg_ctr, HRcInt32, True/*virtual reg*/); +//.. env->vreg_ctr++; +//.. return reg; +//.. } +//.. +//.. static HReg newVRegF ( ISelEnv* env ) +//.. { +//.. HReg reg = mkHReg(env->vreg_ctr, HRcFlt64, True/*virtual reg*/); +//.. env->vreg_ctr++; +//.. return reg; +//.. } +//.. +//.. static HReg newVRegV ( ISelEnv* env ) +//.. { +//.. HReg reg = mkHReg(env->vreg_ctr, HRcVec128, True/*virtual reg*/); +//.. env->vreg_ctr++; +//.. return reg; +//.. } +//.. +//.. +//.. /*---------------------------------------------------------*/ +//.. /*--- ISEL: Forward declarations ---*/ +//.. /*---------------------------------------------------------*/ +//.. +//.. /* These are organised as iselXXX and iselXXX_wrk pairs. The +//.. iselXXX_wrk do the real work, but are not to be called directly. +//.. For each XXX, iselXXX calls its iselXXX_wrk counterpart, then +//.. checks that all returned registers are virtual. You should not +//.. call the _wrk version directly. +//.. */ +//.. static X86RMI* iselIntExpr_RMI_wrk ( ISelEnv* env, IRExpr* e ); +//.. static X86RMI* iselIntExpr_RMI ( ISelEnv* env, IRExpr* e ); +//.. +//.. static X86RI* iselIntExpr_RI_wrk ( ISelEnv* env, IRExpr* e ); +//.. static X86RI* iselIntExpr_RI ( ISelEnv* env, IRExpr* e ); +//.. +//.. static X86RM* iselIntExpr_RM_wrk ( ISelEnv* env, IRExpr* e ); +//.. static X86RM* iselIntExpr_RM ( ISelEnv* env, IRExpr* e ); +//.. +//.. static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e ); +//.. static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e ); +//.. +//.. static X86AMode* iselIntExpr_AMode_wrk ( ISelEnv* env, IRExpr* e ); +//.. static X86AMode* iselIntExpr_AMode ( ISelEnv* env, IRExpr* e ); +//.. +//.. static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo, +//.. ISelEnv* env, IRExpr* e ); +//.. static void iselInt64Expr ( HReg* rHi, HReg* rLo, +//.. ISelEnv* env, IRExpr* e ); +//.. +//.. static X86CondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e ); +//.. static X86CondCode iselCondCode ( ISelEnv* env, IRExpr* e ); +//.. +//.. static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e ); +//.. static HReg iselDblExpr ( ISelEnv* env, IRExpr* e ); +//.. +//.. static HReg iselFltExpr_wrk ( ISelEnv* env, IRExpr* e ); +//.. static HReg iselFltExpr ( ISelEnv* env, IRExpr* e ); +//.. +//.. static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e ); +//.. static HReg iselVecExpr ( ISelEnv* env, IRExpr* e ); +//.. +//.. +//.. /*---------------------------------------------------------*/ +//.. /*--- ISEL: Misc helpers ---*/ +//.. /*---------------------------------------------------------*/ +//.. +//.. /* Is this a 32-bit zero expression? */ +//.. +//.. static Bool isZero32 ( IRExpr* e ) +//.. { +//.. return e->tag == Iex_Const +//.. && e->Iex.Const.con->tag == Ico_U32 +//.. && e->Iex.Const.con->Ico.U32 == 0; +//.. } +//.. +//.. /* Make a int reg-reg move. */ +//.. +//.. static X86Instr* mk_iMOVsd_RR ( HReg src, HReg dst ) +//.. { +//.. vassert(hregClass(src) == HRcInt32); +//.. vassert(hregClass(dst) == HRcInt32); +//.. return X86Instr_Alu32R(Xalu_MOV, X86RMI_Reg(src), dst); +//.. } +//.. +//.. +//.. /* Make a vector reg-reg move. */ +//.. +//.. static X86Instr* mk_vMOVsd_RR ( HReg src, HReg dst ) +//.. { +//.. vassert(hregClass(src) == HRcVec128); +//.. vassert(hregClass(dst) == HRcVec128); +//.. return X86Instr_SseReRg(Xsse_MOV, src, dst); +//.. } +//.. +//.. /* Advance/retreat %esp by n. */ +//.. +//.. static void add_to_esp ( ISelEnv* env, Int n ) +//.. { +//.. vassert(n > 0 && n < 256 && (n%4) == 0); +//.. addInstr(env, +//.. X86Instr_Alu32R(Xalu_ADD, X86RMI_Imm(n), hregX86_ESP())); +//.. } +//.. +//.. static void sub_from_esp ( ISelEnv* env, Int n ) +//.. { +//.. vassert(n > 0 && n < 256 && (n%4) == 0); +//.. addInstr(env, +//.. X86Instr_Alu32R(Xalu_SUB, X86RMI_Imm(n), hregX86_ESP())); +//.. } +//.. +//.. +//.. /* Given an amode, return one which references 4 bytes further +//.. along. */ +//.. +//.. static X86AMode* advance4 ( X86AMode* am ) +//.. { +//.. X86AMode* am4 = dopyX86AMode(am); +//.. switch (am4->tag) { +//.. case Xam_IRRS: +//.. am4->Xam.IRRS.imm += 4; break; +//.. case Xam_IR: +//.. am4->Xam.IR.imm += 4; break; +//.. default: +//.. vpanic("advance4(x86,host)"); +//.. } +//.. return am4; +//.. } +//.. +//.. +//.. /* Push an arg onto the host stack, in preparation for a call to a +//.. helper function of some kind. Returns the number of 32-bit words +//.. pushed. */ +//.. +//.. static Int pushArg ( ISelEnv* env, IRExpr* arg ) +//.. { +//.. IRType arg_ty = typeOfIRExpr(env->type_env, arg); +//.. if (arg_ty == Ity_I32) { +//.. addInstr(env, X86Instr_Push(iselIntExpr_RMI(env, arg))); +//.. return 1; +//.. } else +//.. if (arg_ty == Ity_I64) { +//.. HReg rHi, rLo; +//.. iselInt64Expr(&rHi, &rLo, env, arg); +//.. addInstr(env, X86Instr_Push(X86RMI_Reg(rHi))); +//.. addInstr(env, X86Instr_Push(X86RMI_Reg(rLo))); +//.. return 2; +//.. } +//.. ppIRExpr(arg); +//.. vpanic("pushArg(x86): can't handle arg of this type"); +//.. } +//.. +//.. +//.. /* Complete the call to a helper function, by calling the +//.. helper and clearing the args off the stack. */ +//.. +//.. static +//.. void callHelperAndClearArgs ( ISelEnv* env, X86CondCode cc, +//.. IRCallee* cee, Int n_arg_ws ) +//.. { +//.. /* Complication. Need to decide which reg to use as the fn address +//.. pointer, in a way that doesn't trash regparm-passed +//.. parameters. */ +//.. vassert(sizeof(void*) == 4); +//.. +//.. addInstr(env, X86Instr_Call( cc, (UInt)cee->addr, cee->regparms)); +//.. if (n_arg_ws > 0) +//.. add_to_esp(env, 4*n_arg_ws); +//.. } +//.. +//.. +//.. /* Used only in doHelperCall. See big comment in doHelperCall re +//.. handling of regparm args. This function figures out whether +//.. evaluation of an expression might require use of a fixed register. +//.. If in doubt return True (safe but suboptimal). +//.. */ +//.. static +//.. Bool mightRequireFixedRegs ( IRExpr* e ) +//.. { +//.. switch (e->tag) { +//.. case Iex_Tmp: case Iex_Const: case Iex_Get: +//.. return False; +//.. default: +//.. return True; +//.. } +//.. } +//.. +//.. +//.. /* Do a complete function call. guard is a Ity_Bit expression +//.. indicating whether or not the call happens. If guard==NULL, the +//.. call is unconditional. */ +//.. +//.. static +//.. void doHelperCall ( ISelEnv* env, +//.. Bool passBBP, +//.. IRExpr* guard, IRCallee* cee, IRExpr** args ) +//.. { +//.. X86CondCode cc; +//.. HReg argregs[3]; +//.. HReg tmpregs[3]; +//.. Bool danger; +//.. Int not_done_yet, n_args, n_arg_ws, stack_limit, +//.. i, argreg, argregX; +//.. +//.. /* Marshal args for a call, do the call, and clear the stack. +//.. Complexities to consider: +//.. +//.. * if passBBP is True, %ebp (the baseblock pointer) is to be +//.. passed as the first arg. +//.. +//.. * If the callee claims regparmness of 1, 2 or 3, we must pass the +//.. first 1, 2 or 3 args in registers (EAX, EDX, and ECX +//.. respectively). To keep things relatively simple, only args of +//.. type I32 may be passed as regparms -- just bomb out if anything +//.. else turns up. Clearly this depends on the front ends not +//.. trying to pass any other types as regparms. +//.. */ +//.. +//.. /* 16 Nov 2004: the regparm handling is complicated by the +//.. following problem. +//.. +//.. Consider a call two a function with two regparm parameters: +//.. f(e1,e2). We need to compute e1 into %eax and e2 into %edx. +//.. Suppose code is first generated to compute e1 into %eax. Then, +//.. code is generated to compute e2 into %edx. Unfortunately, if +//.. the latter code sequence uses %eax, it will trash the value of +//.. e1 computed by the former sequence. This could happen if (for +//.. example) e2 itself involved a function call. In the code below, +//.. args are evaluated right-to-left, not left-to-right, but the +//.. principle and the problem are the same. +//.. +//.. One solution is to compute all regparm-bound args into vregs +//.. first, and once they are all done, move them to the relevant +//.. real regs. This always gives correct code, but it also gives +//.. a bunch of vreg-to-rreg moves which are usually redundant but +//.. are hard for the register allocator to get rid of. +//.. +//.. A compromise is to first examine all regparm'd argument +//.. expressions. If they are all so simple that it is clear +//.. they will be evaluated without use of any fixed registers, +//.. use the old compute-directly-to-fixed-target scheme. If not, +//.. be safe and use the via-vregs scheme. +//.. +//.. Note this requires being able to examine an expression and +//.. determine whether or not evaluation of it might use a fixed +//.. register. That requires knowledge of how the rest of this +//.. insn selector works. Currently just the following 3 are +//.. regarded as safe -- hopefully they cover the majority of +//.. arguments in practice: IRExpr_Tmp IRExpr_Const IRExpr_Get. +//.. */ +//.. vassert(cee->regparms >= 0 && cee->regparms <= 3); +//.. +//.. n_args = n_arg_ws = 0; +//.. while (args[n_args]) n_args++; +//.. +//.. not_done_yet = n_args; +//.. if (passBBP) +//.. not_done_yet++; +//.. +//.. stack_limit = cee->regparms; +//.. if (cee->regparms > 0 && passBBP) stack_limit--; +//.. +//.. /* ------ BEGIN marshall all arguments ------ */ +//.. +//.. /* Push (R to L) the stack-passed args, [n_args-1 .. stack_limit] */ +//.. for (i = n_args-1; i >= stack_limit; i--) { +//.. n_arg_ws += pushArg(env, args[i]); +//.. not_done_yet--; +//.. } +//.. +//.. /* args [stack_limit-1 .. 0] and possibly %ebp are to be passed in +//.. registers. */ +//.. +//.. if (cee->regparms > 0) { +//.. +//.. /* ------ BEGIN deal with regparms ------ */ +//.. +//.. /* deal with regparms, not forgetting %ebp if needed. */ +//.. argregs[0] = hregX86_EAX(); +//.. argregs[1] = hregX86_EDX(); +//.. argregs[2] = hregX86_ECX(); +//.. tmpregs[0] = tmpregs[1] = tmpregs[2] = INVALID_HREG; +//.. +//.. argreg = cee->regparms; +//.. +//.. /* In keeping with big comment above, detect potential danger +//.. and use the via-vregs scheme if needed. */ +//.. danger = False; +//.. for (i = stack_limit-1; i >= 0; i--) { +//.. if (mightRequireFixedRegs(args[i])) { +//.. danger = True; +//.. break; +//.. } +//.. } +//.. +//.. if (danger) { +//.. +//.. /* Move via temporaries */ +//.. argregX = argreg; +//.. for (i = stack_limit-1; i >= 0; i--) { +//.. +//.. if (0) { +//.. vex_printf("x86 host: register param is complex: "); +//.. ppIRExpr(args[i]); +//.. vex_printf("\n"); +//.. } +//.. +//.. argreg--; +//.. vassert(argreg >= 0); +//.. vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32); +//.. tmpregs[argreg] = iselIntExpr_R(env, args[i]); +//.. not_done_yet--; +//.. } +//.. for (i = stack_limit-1; i >= 0; i--) { +//.. argregX--; +//.. vassert(argregX >= 0); +//.. addInstr( env, mk_iMOVsd_RR( tmpregs[argregX], argregs[argregX] ) ); +//.. } +//.. +//.. } else { +//.. /* It's safe to compute all regparm args directly into their +//.. target registers. */ +//.. for (i = stack_limit-1; i >= 0; i--) { +//.. argreg--; +//.. vassert(argreg >= 0); +//.. vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32); +//.. addInstr(env, X86Instr_Alu32R(Xalu_MOV, +//.. iselIntExpr_RMI(env, args[i]), +//.. argregs[argreg])); +//.. not_done_yet--; +//.. } +//.. +//.. } +//.. +//.. /* Not forgetting %ebp if needed. */ +//.. if (passBBP) { +//.. vassert(argreg == 1); +//.. addInstr(env, mk_iMOVsd_RR( hregX86_EBP(), argregs[0])); +//.. not_done_yet--; +//.. } +//.. +//.. /* ------ END deal with regparms ------ */ +//.. +//.. } else { +//.. +//.. /* No regparms. Heave %ebp on the stack if needed. */ +//.. if (passBBP) { +//.. addInstr(env, X86Instr_Push(X86RMI_Reg(hregX86_EBP()))); +//.. n_arg_ws++; +//.. not_done_yet--; +//.. } +//.. +//.. } +//.. +//.. vassert(not_done_yet == 0); +//.. +//.. /* ------ END marshall all arguments ------ */ +//.. +//.. /* Now we can compute the condition. We can't do it earlier +//.. because the argument computations could trash the condition +//.. codes. Be a bit clever to handle the common case where the +//.. guard is 1:Bit. */ +//.. cc = Xcc_ALWAYS; +//.. if (guard) { +//.. if (guard->tag == Iex_Const +//.. && guard->Iex.Const.con->tag == Ico_U1 +//.. && guard->Iex.Const.con->Ico.U1 == True) { +//.. /* unconditional -- do nothing */ +//.. } else { +//.. cc = iselCondCode( env, guard ); +//.. } +//.. } +//.. +//.. /* call the helper, and get the args off the stack afterwards. */ +//.. callHelperAndClearArgs( env, cc, cee, n_arg_ws ); +//.. } +//.. +//.. +//.. /* Given a guest-state array descriptor, an index expression and a +//.. bias, generate an X86AMode holding the relevant guest state +//.. offset. */ +//.. +//.. static +//.. X86AMode* genGuestArrayOffset ( ISelEnv* env, IRArray* descr, +//.. IRExpr* off, Int bias ) +//.. { +//.. HReg tmp, roff; +//.. Int elemSz = sizeofIRType(descr->elemTy); +//.. Int nElems = descr->nElems; +//.. +//.. /* throw out any cases not generated by an x86 front end. In +//.. theory there might be a day where we need to handle them -- if +//.. we ever run non-x86-guest on x86 host. */ +//.. +//.. if (nElems != 8 || (elemSz != 1 && elemSz != 8)) +//.. vpanic("genGuestArrayOffset(x86 host)"); +//.. +//.. /* Compute off into a reg, %off. Then return: +//.. +//.. movl %off, %tmp +//.. addl $bias, %tmp (if bias != 0) +//.. andl %tmp, 7 +//.. ... base(%ebp, %tmp, shift) ... +//.. */ +//.. tmp = newVRegI(env); +//.. roff = iselIntExpr_R(env, off); +//.. addInstr(env, mk_iMOVsd_RR(roff, tmp)); +//.. if (bias != 0) { +//.. addInstr(env, +//.. X86Instr_Alu32R(Xalu_ADD, X86RMI_Imm(bias), tmp)); +//.. } +//.. addInstr(env, +//.. X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(7), tmp)); +//.. vassert(elemSz == 1 || elemSz == 8); +//.. return +//.. X86AMode_IRRS( descr->base, hregX86_EBP(), tmp, +//.. elemSz==8 ? 3 : 0); +//.. } +//.. +//.. +//.. /* Mess with the FPU's rounding mode: set to the default rounding mode +//.. (DEFAULT_FPUCW). */ +//.. static +//.. void set_FPU_rounding_default ( ISelEnv* env ) +//.. { +//.. /* pushl $DEFAULT_FPUCW +//.. fldcw 0(%esp) +//.. addl $4, %esp +//.. */ +//.. X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP()); +//.. addInstr(env, X86Instr_Push(X86RMI_Imm(DEFAULT_FPUCW))); +//.. addInstr(env, X86Instr_FpLdStCW(True/*load*/, zero_esp)); +//.. add_to_esp(env, 4); +//.. } +//.. +//.. +//.. /* Mess with the FPU's rounding mode: 'mode' is an I32-typed +//.. expression denoting a value in the range 0 .. 3, indicating a round +//.. mode encoded as per type IRRoundingMode. Set the x87 FPU to have +//.. the same rounding. +//.. */ +//.. static +//.. void set_FPU_rounding_mode ( ISelEnv* env, IRExpr* mode ) +//.. { +//.. HReg rrm = iselIntExpr_R(env, mode); +//.. HReg rrm2 = newVRegI(env); +//.. X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP()); +//.. +//.. /* movl %rrm, %rrm2 +//.. andl $3, %rrm2 -- shouldn't be needed; paranoia +//.. shll $10, %rrm2 +//.. orl $DEFAULT_FPUCW, %rrm2 +//.. pushl %rrm2 +//.. fldcw 0(%esp) +//.. addl $4, %esp +//.. */ +//.. addInstr(env, mk_iMOVsd_RR(rrm, rrm2)); +//.. addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(3), rrm2)); +//.. addInstr(env, X86Instr_Sh32(Xsh_SHL, 10, X86RM_Reg(rrm2))); +//.. addInstr(env, X86Instr_Alu32R(Xalu_OR, X86RMI_Imm(DEFAULT_FPUCW), rrm2)); +//.. addInstr(env, X86Instr_Push(X86RMI_Reg(rrm2))); +//.. addInstr(env, X86Instr_FpLdStCW(True/*load*/, zero_esp)); +//.. add_to_esp(env, 4); +//.. } +//.. +//.. +//.. /* Generate !src into a new vector register, and be sure that the code +//.. is SSE1 compatible. Amazing that Intel doesn't offer a less crappy +//.. way to do this. +//.. */ +//.. static HReg do_sse_Not128 ( ISelEnv* env, HReg src ) +//.. { +//.. HReg dst = newVRegV(env); +//.. /* Set dst to zero. Not strictly necessary, but the idea of doing +//.. a FP comparison on whatever junk happens to be floating around +//.. in it is just too scary. */ +//.. addInstr(env, X86Instr_SseReRg(Xsse_XOR, dst, dst)); +//.. /* And now make it all 1s ... */ +//.. addInstr(env, X86Instr_Sse32Fx4(Xsse_CMPEQF, dst, dst)); +//.. /* Finally, xor 'src' into it. */ +//.. addInstr(env, X86Instr_SseReRg(Xsse_XOR, src, dst)); +//.. return dst; +//.. } +//.. +//.. +//.. /* Round an x87 FPU value to 53-bit-mantissa precision, to be used +//.. after most non-simple FPU operations (simple = +, -, *, / and +//.. sqrt). +//.. +//.. This could be done a lot more efficiently if needed, by loading +//.. zero and adding it to the value to be rounded (fldz ; faddp?). +//.. */ +//.. static void roundToF64 ( ISelEnv* env, HReg reg ) +//.. { +//.. X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP()); +//.. sub_from_esp(env, 8); +//.. addInstr(env, X86Instr_FpLdSt(False/*store*/, 8, reg, zero_esp)); +//.. addInstr(env, X86Instr_FpLdSt(True/*load*/, 8, reg, zero_esp)); +//.. add_to_esp(env, 8); +//.. } +//.. +//.. +//.. /*---------------------------------------------------------*/ +//.. /*--- ISEL: Integer expressions (32/16/8 bit) ---*/ +//.. /*---------------------------------------------------------*/ +//.. +//.. /* Select insns for an integer-typed expression, and add them to the +//.. code list. Return a reg holding the result. This reg will be a +//.. virtual register. THE RETURNED REG 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. +//.. +//.. This should handle expressions of 32, 16 and 8-bit type. All +//.. results are returned in a 32-bit register. For 16- and 8-bit +//.. expressions, the upper 16/24 bits are arbitrary, so you should mask +//.. or sign extend partial values if necessary. +//.. */ +//.. +//.. static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e ) +//.. { +//.. HReg r = iselIntExpr_R_wrk(env, e); +//.. /* sanity checks ... */ +//.. # if 0 +//.. vex_printf("\n"); ppIRExpr(e); vex_printf("\n"); +//.. # endif +//.. vassert(hregClass(r) == HRcInt32); +//.. vassert(hregIsVirtual(r)); +//.. return r; +//.. } +//.. +//.. /* DO NOT CALL THIS DIRECTLY ! */ +//.. static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e ) +//.. { +//.. MatchInfo mi; +//.. DECLARE_PATTERN(p_32to1_then_1Uto8); +//.. +//.. IRType ty = typeOfIRExpr(env->type_env,e); +//.. vassert(ty == Ity_I32 || Ity_I16 || Ity_I8); +//.. +//.. switch (e->tag) { +//.. +//.. /* --------- TEMP --------- */ +//.. case Iex_Tmp: { +//.. return lookupIRTemp(env, e->Iex.Tmp.tmp); +//.. } +//.. +//.. /* --------- LOAD --------- */ +//.. case Iex_LDle: { +//.. HReg dst = newVRegI(env); +//.. X86AMode* amode = iselIntExpr_AMode ( env, e->Iex.LDle.addr ); +//.. if (ty == Ity_I32) { +//.. addInstr(env, X86Instr_Alu32R(Xalu_MOV, +//.. X86RMI_Mem(amode), dst) ); +//.. return dst; +//.. } +//.. if (ty == Ity_I16) { +//.. addInstr(env, X86Instr_LoadEX(2,False,amode,dst)); +//.. return dst; +//.. } +//.. if (ty == Ity_I8) { +//.. addInstr(env, X86Instr_LoadEX(1,False,amode,dst)); +//.. return dst; +//.. } +//.. break; +//.. } +//.. +//.. /* --------- BINARY OP --------- */ +//.. case Iex_Binop: { +//.. X86AluOp aluOp; +//.. X86ShiftOp shOp; +//.. +//.. /* Pattern: Sub32(0,x) */ +//.. if (e->Iex.Binop.op == Iop_Sub32 && isZero32(e->Iex.Binop.arg1)) { +//.. HReg dst = newVRegI(env); +//.. HReg reg = iselIntExpr_R(env, e->Iex.Binop.arg2); +//.. addInstr(env, mk_iMOVsd_RR(reg,dst)); +//.. addInstr(env, X86Instr_Unary32(Xun_NEG,X86RM_Reg(dst))); +//.. return dst; +//.. } +//.. +//.. /* Is it an addition or logical style op? */ +//.. switch (e->Iex.Binop.op) { +//.. case Iop_Add8: case Iop_Add16: case Iop_Add32: +//.. aluOp = Xalu_ADD; break; +//.. case Iop_Sub8: case Iop_Sub16: case Iop_Sub32: +//.. aluOp = Xalu_SUB; break; +//.. case Iop_And8: case Iop_And16: case Iop_And32: +//.. aluOp = Xalu_AND; break; +//.. case Iop_Or8: case Iop_Or16: case Iop_Or32: +//.. aluOp = Xalu_OR; break; +//.. case Iop_Xor8: case Iop_Xor16: case Iop_Xor32: +//.. aluOp = Xalu_XOR; break; +//.. case Iop_Mul16: case Iop_Mul32: +//.. aluOp = Xalu_MUL; break; +//.. default: +//.. aluOp = Xalu_INVALID; break; +//.. } +//.. /* For commutative ops we assume any literal +//.. values are on the second operand. */ +//.. if (aluOp != Xalu_INVALID) { +//.. HReg dst = newVRegI(env); +//.. HReg reg = iselIntExpr_R(env, e->Iex.Binop.arg1); +//.. X86RMI* rmi = iselIntExpr_RMI(env, e->Iex.Binop.arg2); +//.. addInstr(env, mk_iMOVsd_RR(reg,dst)); +//.. addInstr(env, X86Instr_Alu32R(aluOp, rmi, dst)); +//.. return dst; +//.. } +//.. /* Could do better here; forcing the first arg into a reg +//.. isn't always clever. +//.. -- t70 = Xor32(And32(Xor32(LDle:I32(Add32(t41,0xFFFFFFA0:I32)), +//.. LDle:I32(Add32(t41,0xFFFFFFA4:I32))),LDle:I32(Add32( +//.. t41,0xFFFFFFA8:I32))),LDle:I32(Add32(t41,0xFFFFFFA0:I32))) +//.. movl 0xFFFFFFA0(%vr41),%vr107 +//.. movl 0xFFFFFFA4(%vr41),%vr108 +//.. movl %vr107,%vr106 +//.. xorl %vr108,%vr106 +//.. movl 0xFFFFFFA8(%vr41),%vr109 +//.. movl %vr106,%vr105 +//.. andl %vr109,%vr105 +//.. movl 0xFFFFFFA0(%vr41),%vr110 +//.. movl %vr105,%vr104 +//.. xorl %vr110,%vr104 +//.. movl %vr104,%vr70 +//.. */ +//.. +//.. /* Perhaps a shift op? */ +//.. switch (e->Iex.Binop.op) { +//.. case Iop_Shl32: case Iop_Shl16: case Iop_Shl8: +//.. shOp = Xsh_SHL; break; +//.. case Iop_Shr32: case Iop_Shr16: case Iop_Shr8: +//.. shOp = Xsh_SHR; break; +//.. case Iop_Sar32: case Iop_Sar16: case Iop_Sar8: +//.. shOp = Xsh_SAR; break; +//.. default: +//.. shOp = Xsh_INVALID; break; +//.. } +//.. if (shOp != Xsh_INVALID) { +//.. HReg dst = newVRegI(env); +//.. +//.. /* regL = the value to be shifted */ +//.. HReg regL = iselIntExpr_R(env, e->Iex.Binop.arg1); +//.. addInstr(env, mk_iMOVsd_RR(regL,dst)); +//.. +//.. /* Do any necessary widening for 16/8 bit operands */ +//.. switch (e->Iex.Binop.op) { +//.. case Iop_Shr8: +//.. addInstr(env, X86Instr_Alu32R( +//.. Xalu_AND, X86RMI_Imm(0xFF), dst)); +//.. break; +//.. case Iop_Shr16: +//.. addInstr(env, X86Instr_Alu32R( +//.. Xalu_AND, X86RMI_Imm(0xFFFF), dst)); +//.. break; +//.. case Iop_Sar8: +//.. addInstr(env, X86Instr_Sh32(Xsh_SHL, 24, X86RM_Reg(dst))); +//.. addInstr(env, X86Instr_Sh32(Xsh_SAR, 24, X86RM_Reg(dst))); +//.. break; +//.. case Iop_Sar16: +//.. addInstr(env, X86Instr_Sh32(Xsh_SHL, 16, X86RM_Reg(dst))); +//.. addInstr(env, X86Instr_Sh32(Xsh_SAR, 16, X86RM_Reg(dst))); +//.. break; +//.. default: break; +//.. } +//.. +//.. /* Now consider the shift amount. If it's a literal, we +//.. can do a much better job than the general case. */ +//.. if (e->Iex.Binop.arg2->tag == Iex_Const) { +//.. /* assert that the IR is well-typed */ +//.. Int nshift; +//.. vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8); +//.. nshift = e->Iex.Binop.arg2->Iex.Const.con->Ico.U8; +//.. vassert(nshift >= 0); +//.. if (nshift > 0) +//.. /* Can't allow nshift==0 since that means %cl */ +//.. addInstr(env, X86Instr_Sh32( +//.. shOp, +//.. nshift, +//.. X86RM_Reg(dst))); +//.. } else { +//.. /* General case; we have to force the amount into %cl. */ +//.. HReg regR = iselIntExpr_R(env, e->Iex.Binop.arg2); +//.. addInstr(env, mk_iMOVsd_RR(regR,hregX86_ECX())); +//.. addInstr(env, X86Instr_Sh32(shOp, 0/* %cl */, X86RM_Reg(dst))); +//.. } +//.. return dst; +//.. } +//.. +//.. /* Handle misc other ops. */ +//.. if (e->Iex.Binop.op == Iop_8HLto16) { +//.. HReg hi8 = newVRegI(env); +//.. HReg lo8 = newVRegI(env); +//.. HReg hi8s = iselIntExpr_R(env, e->Iex.Binop.arg1); +//.. HReg lo8s = iselIntExpr_R(env, e->Iex.Binop.arg2); +//.. addInstr(env, mk_iMOVsd_RR(hi8s, hi8)); +//.. addInstr(env, mk_iMOVsd_RR(lo8s, lo8)); +//.. addInstr(env, X86Instr_Sh32(Xsh_SHL, 8, X86RM_Reg(hi8))); +//.. addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(0xFF), lo8)); +//.. addInstr(env, X86Instr_Alu32R(Xalu_OR, X86RMI_Reg(lo8), hi8)); +//.. return hi8; +//.. } +//.. +//.. if (e->Iex.Binop.op == Iop_16HLto32) { +//.. HReg hi16 = newVRegI(env); +//.. HReg lo16 = newVRegI(env); +//.. HReg hi16s = iselIntExpr_R(env, e->Iex.Binop.arg1); +//.. HReg lo16s = iselIntExpr_R(env, e->Iex.Binop.arg2); +//.. addInstr(env, mk_iMOVsd_RR(hi16s, hi16)); +//.. addInstr(env, mk_iMOVsd_RR(lo16s, lo16)); +//.. addInstr(env, X86Instr_Sh32(Xsh_SHL, 16, X86RM_Reg(hi16))); +//.. addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(0xFFFF), lo16)); +//.. addInstr(env, X86Instr_Alu32R(Xalu_OR, X86RMI_Reg(lo16), hi16)); +//.. return hi16; +//.. } +//.. +//.. if (e->Iex.Binop.op == Iop_MullS16 || e->Iex.Binop.op == Iop_MullS8 +//.. || e->Iex.Binop.op == Iop_MullU16 || e->Iex.Binop.op == Iop_MullU8) { +//.. HReg a16 = newVRegI(env); +//.. HReg b16 = newVRegI(env); +//.. HReg a16s = iselIntExpr_R(env, e->Iex.Binop.arg1); +//.. HReg b16s = iselIntExpr_R(env, e->Iex.Binop.arg2); +//.. Int shift = (e->Iex.Binop.op == Iop_MullS8 +//.. || e->Iex.Binop.op == Iop_MullU8) +//.. ? 24 : 16; +//.. X86ShiftOp shr_op = (e->Iex.Binop.op == Iop_MullS8 +//.. || e->Iex.Binop.op == Iop_MullS16) +//.. ? Xsh_SAR : Xsh_SHR; +//.. +//.. addInstr(env, mk_iMOVsd_RR(a16s, a16)); +//.. addInstr(env, mk_iMOVsd_RR(b16s, b16)); +//.. addInstr(env, X86Instr_Sh32(Xsh_SHL, shift, X86RM_Reg(a16))); +//.. addInstr(env, X86Instr_Sh32(Xsh_SHL, shift, X86RM_Reg(b16))); +//.. addInstr(env, X86Instr_Sh32(shr_op, shift, X86RM_Reg(a16))); +//.. addInstr(env, X86Instr_Sh32(shr_op, shift, X86RM_Reg(b16))); +//.. addInstr(env, X86Instr_Alu32R(Xalu_MUL, X86RMI_Reg(a16), b16)); +//.. return b16; +//.. } +//.. +//.. if (e->Iex.Binop.op == Iop_CmpF64) { +//.. HReg fL = iselDblExpr(env, e->Iex.Binop.arg1); +//.. HReg fR = iselDblExpr(env, e->Iex.Binop.arg2); +//.. HReg dst = newVRegI(env); +//.. addInstr(env, X86Instr_FpCmp(fL,fR,dst)); +//.. /* shift this right 8 bits so as to conform to CmpF64 +//.. definition. */ +//.. addInstr(env, X86Instr_Sh32(Xsh_SHR, 8, X86RM_Reg(dst))); +//.. return dst; +//.. } +//.. +//.. if (e->Iex.Binop.op == Iop_F64toI32 || e->Iex.Binop.op == Iop_F64toI16) { +//.. Int sz = e->Iex.Binop.op == Iop_F64toI16 ? 2 : 4; +//.. HReg rf = iselDblExpr(env, e->Iex.Binop.arg2); +//.. HReg dst = newVRegI(env); +//.. +//.. /* Used several times ... */ +//.. X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP()); +//.. +//.. /* rf now holds the value to be converted, and rrm holds the +//.. rounding mode value, encoded as per the IRRoundingMode +//.. enum. The first thing to do is set the FPU's rounding +//.. mode accordingly. */ +//.. +//.. /* Create a space for the format conversion. */ +//.. /* subl $4, %esp */ +//.. sub_from_esp(env, 4); +//.. +//.. /* Set host rounding mode */ +//.. set_FPU_rounding_mode( env, e->Iex.Binop.arg1 ); +//.. +//.. /* gistw/l %rf, 0(%esp) */ +//.. addInstr(env, X86Instr_FpLdStI(False/*store*/, sz, rf, zero_esp)); +//.. +//.. if (sz == 2) { +//.. /* movzwl 0(%esp), %dst */ +//.. addInstr(env, X86Instr_LoadEX(2,False,zero_esp,dst)); +//.. } else { +//.. /* movl 0(%esp), %dst */ +//.. vassert(sz == 4); +//.. addInstr(env, X86Instr_Alu32R( +//.. Xalu_MOV, X86RMI_Mem(zero_esp), dst)); +//.. } +//.. +//.. /* Restore default FPU rounding. */ +//.. set_FPU_rounding_default( env ); +//.. +//.. /* addl $4, %esp */ +//.. add_to_esp(env, 4); +//.. return dst; +//.. } +//.. +//.. /* C3210 flags following FPU partial remainder (fprem), both +//.. IEEE compliant (PREM1) and non-IEEE compliant (PREM). */ +//.. if (e->Iex.Binop.op == Iop_PRemC3210F64 +//.. || e->Iex.Binop.op == Iop_PRem1C3210F64) { +//.. HReg junk = newVRegF(env); +//.. HReg dst = newVRegI(env); +//.. HReg srcL = iselDblExpr(env, e->Iex.Binop.arg1); +//.. HReg srcR = iselDblExpr(env, e->Iex.Binop.arg2); +//.. addInstr(env, X86Instr_FpBinary( +//.. e->Iex.Binop.op==Iop_PRemC3210F64 +//.. ? Xfp_PREM : Xfp_PREM1, +//.. srcL,srcR,junk +//.. )); +//.. /* The previous pseudo-insn will have left the FPU's C3210 +//.. flags set correctly. So bag them. */ +//.. addInstr(env, X86Instr_FpStSW_AX()); +//.. addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), dst)); +//.. addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(0x4700), dst)); +//.. return dst; +//.. } +//.. +//.. break; +//.. } +//.. +//.. /* --------- UNARY OP --------- */ +//.. case Iex_Unop: { +//.. /* 1Uto8(32to1(expr32)) */ +//.. DEFINE_PATTERN(p_32to1_then_1Uto8, +//.. unop(Iop_1Uto8,unop(Iop_32to1,bind(0)))); +//.. if (matchIRExpr(&mi,p_32to1_then_1Uto8,e)) { +//.. IRExpr* expr32 = mi.bindee[0]; +//.. HReg dst = newVRegI(env); +//.. HReg src = iselIntExpr_R(env, expr32); +//.. addInstr(env, mk_iMOVsd_RR(src,dst) ); +//.. addInstr(env, X86Instr_Alu32R(Xalu_AND, +//.. X86RMI_Imm(1), dst)); +//.. return dst; +//.. } +//.. +//.. /* 16Uto32(LDle(expr32)) */ +//.. { +//.. DECLARE_PATTERN(p_LDle16_then_16Uto32); +//.. DEFINE_PATTERN(p_LDle16_then_16Uto32, +//.. unop(Iop_16Uto32,IRExpr_LDle(Ity_I16,bind(0))) ); +//.. if (matchIRExpr(&mi,p_LDle16_then_16Uto32,e)) { +//.. HReg dst = newVRegI(env); +//.. X86AMode* amode = iselIntExpr_AMode ( env, mi.bindee[0] ); +//.. addInstr(env, X86Instr_LoadEX(2,False,amode,dst)); +//.. return dst; +//.. } +//.. } +//.. +//.. switch (e->Iex.Unop.op) { +//.. case Iop_8Uto16: +//.. case Iop_8Uto32: +//.. case Iop_16Uto32: { +//.. HReg dst = newVRegI(env); +//.. HReg src = iselIntExpr_R(env, e->Iex.Unop.arg); +//.. UInt mask = e->Iex.Unop.op==Iop_16Uto32 ? 0xFFFF : 0xFF; +//.. addInstr(env, mk_iMOVsd_RR(src,dst) ); +//.. addInstr(env, X86Instr_Alu32R(Xalu_AND, +//.. X86RMI_Imm(mask), dst)); +//.. return dst; +//.. } +//.. case Iop_8Sto16: +//.. case Iop_8Sto32: +//.. case Iop_16Sto32: { +//.. HReg dst = newVRegI(env); +//.. HReg src = iselIntExpr_R(env, e->Iex.Unop.arg); +//.. UInt amt = e->Iex.Unop.op==Iop_16Sto32 ? 16 : 24; +//.. addInstr(env, mk_iMOVsd_RR(src,dst) ); +//.. addInstr(env, X86Instr_Sh32(Xsh_SHL, amt, X86RM_Reg(dst))); +//.. addInstr(env, X86Instr_Sh32(Xsh_SAR, amt, X86RM_Reg(dst))); +//.. return dst; +//.. } +//.. case Iop_Not8: +//.. case Iop_Not16: +//.. case Iop_Not32: { +//.. HReg dst = newVRegI(env); +//.. HReg src = iselIntExpr_R(env, e->Iex.Unop.arg); +//.. addInstr(env, mk_iMOVsd_RR(src,dst) ); +//.. addInstr(env, X86Instr_Unary32(Xun_NOT,X86RM_Reg(dst))); +//.. return dst; +//.. } +//.. case Iop_64HIto32: { +//.. HReg rHi, rLo; +//.. iselInt64Expr(&rHi,&rLo, env, e->Iex.Unop.arg); +//.. return rHi; /* and abandon rLo .. poor wee thing :-) */ +//.. } +//.. case Iop_64to32: { +//.. HReg rHi, rLo; +//.. iselInt64Expr(&rHi,&rLo, env, e->Iex.Unop.arg); +//.. return rLo; /* similar stupid comment to the above ... */ +//.. } +//.. case Iop_16HIto8: +//.. case Iop_32HIto16: { +//.. HReg dst = newVRegI(env); +//.. HReg src = iselIntExpr_R(env, e->Iex.Unop.arg); +//.. Int shift = e->Iex.Unop.op == Iop_16HIto8 ? 8 : 16; +//.. addInstr(env, mk_iMOVsd_RR(src,dst) ); +//.. addInstr(env, X86Instr_Sh32(Xsh_SHR, shift, X86RM_Reg(dst))); +//.. return dst; +//.. } +//.. case Iop_1Uto32: +//.. case Iop_1Uto8: { +//.. HReg dst = newVRegI(env); +//.. X86CondCode cond = iselCondCode(env, e->Iex.Unop.arg); +//.. addInstr(env, X86Instr_Set32(cond,dst)); +//.. return dst; +//.. } +//.. case Iop_1Sto8: +//.. case Iop_1Sto16: +//.. case Iop_1Sto32: { +//.. /* could do better than this, but for now ... */ +//.. HReg dst = newVRegI(env); +//.. X86CondCode cond = iselCondCode(env, e->Iex.Unop.arg); +//.. addInstr(env, X86Instr_Set32(cond,dst)); +//.. addInstr(env, X86Instr_Sh32(Xsh_SHL, 31, X86RM_Reg(dst))); +//.. addInstr(env, X86Instr_Sh32(Xsh_SAR, 31, X86RM_Reg(dst))); +//.. return dst; +//.. } +//.. case Iop_Ctz32: { +//.. /* Count trailing zeroes, implemented by x86 'bsfl' */ +//.. HReg dst = newVRegI(env); +//.. HReg src = iselIntExpr_R(env, e->Iex.Unop.arg); +//.. addInstr(env, X86Instr_Bsfr32(True,src,dst)); +//.. return dst; +//.. } +//.. case Iop_Clz32: { +//.. /* Count leading zeroes. Do 'bsrl' to establish the index +//.. of the highest set bit, and subtract that value from +//.. 31. */ +//.. HReg tmp = newVRegI(env); +//.. HReg dst = newVRegI(env); +//.. HReg src = iselIntExpr_R(env, e->Iex.Unop.arg); +//.. addInstr(env, X86Instr_Bsfr32(False,src,tmp)); +//.. addInstr(env, X86Instr_Alu32R(Xalu_MOV, +//.. X86RMI_Imm(31), dst)); +//.. addInstr(env, X86Instr_Alu32R(Xalu_SUB, +//.. X86RMI_Reg(tmp), dst)); +//.. return dst; +//.. } +//.. +//.. case Iop_128to32: { +//.. HReg dst = newVRegI(env); +//.. HReg vec = iselVecExpr(env, e->Iex.Unop.arg); +//.. X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP()); +//.. sub_from_esp(env, 16); +//.. addInstr(env, X86Instr_SseLdSt(False/*store*/, vec, esp0)); +//.. addInstr(env, X86Instr_Alu32R( Xalu_MOV, X86RMI_Mem(esp0), dst )); +//.. add_to_esp(env, 16); +//.. return dst; +//.. } +//.. +//.. case Iop_16to8: +//.. case Iop_32to8: +//.. case Iop_32to16: +//.. /* These are no-ops. */ +//.. return iselIntExpr_R(env, e->Iex.Unop.arg); +//.. +//.. default: +//.. break; +//.. } +//.. break; +//.. } +//.. +//.. /* --------- GET --------- */ +//.. case Iex_Get: { +//.. if (ty == Ity_I32) { +//.. HReg dst = newVRegI(env); +//.. addInstr(env, X86Instr_Alu32R( +//.. Xalu_MOV, +//.. X86RMI_Mem(X86AMode_IR(e->Iex.Get.offset, +//.. hregX86_EBP())), +//.. dst)); +//.. return dst; +//.. } +//.. if (ty == Ity_I8 || ty == Ity_I16) { +//.. HReg dst = newVRegI(env); +//.. addInstr(env, X86Instr_LoadEX( +//.. ty==Ity_I8 ? 1 : 2, +//.. False, +//.. X86AMode_IR(e->Iex.Get.offset,hregX86_EBP()), +//.. dst)); +//.. return dst; +//.. } +//.. break; +//.. } +//.. +//.. case Iex_GetI: { +//.. X86AMode* am +//.. = genGuestArrayOffset( +//.. env, e->Iex.GetI.descr, +//.. e->Iex.GetI.ix, e->Iex.GetI.bias ); +//.. HReg dst = newVRegI(env); +//.. if (ty == Ity_I8) { +//.. addInstr(env, X86Instr_LoadEX( 1, False, am, dst )); +//.. return dst; +//.. } +//.. break; +//.. } +//.. +//.. /* --------- CCALL --------- */ +//.. case Iex_CCall: { +//.. HReg dst = newVRegI(env); +//.. vassert(ty == Ity_I32); +//.. +//.. /* be very restrictive for now. Only 32/64-bit ints allowed +//.. for args, and 32 bits for return type. */ +//.. if (e->Iex.CCall.retty != Ity_I32) +//.. goto irreducible; +//.. +//.. /* Marshal args, do the call, clear stack. */ +//.. doHelperCall( env, False, NULL, e->Iex.CCall.cee, e->Iex.CCall.args ); +//.. +//.. addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), dst)); +//.. return dst; +//.. } +//.. +//.. /* --------- LITERAL --------- */ +//.. /* 32/16/8-bit literals */ +//.. case Iex_Const: { +//.. X86RMI* rmi = iselIntExpr_RMI ( env, e ); +//.. HReg r = newVRegI(env); +//.. addInstr(env, X86Instr_Alu32R(Xalu_MOV, rmi, r)); +//.. return r; +//.. } +//.. +//.. /* --------- MULTIPLEX --------- */ +//.. case Iex_Mux0X: { +//.. if ((ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8) +//.. && typeOfIRExpr(env->type_env,e->Iex.Mux0X.cond) == Ity_I8) { +//.. HReg r8; +//.. HReg rX = iselIntExpr_R(env, e->Iex.Mux0X.exprX); +//.. X86RM* r0 = iselIntExpr_RM(env, e->Iex.Mux0X.expr0); +//.. HReg dst = newVRegI(env); +//.. addInstr(env, mk_iMOVsd_RR(rX,dst)); +//.. r8 = iselIntExpr_R(env, e->Iex.Mux0X.cond); +//.. addInstr(env, X86Instr_Test32(X86RI_Imm(0xFF), X86RM_Reg(r8))); +//.. addInstr(env, X86Instr_CMov32(Xcc_Z,r0,dst)); +//.. return dst; +//.. } +//.. break; +//.. } +//.. +//.. default: +//.. break; +//.. } /* switch (e->tag) */ +//.. +//.. /* We get here if no pattern matched. */ +//.. irreducible: +//.. ppIRExpr(e); +//.. vpanic("iselIntExpr_R: cannot reduce tree"); +//.. } +//.. +//.. +//.. /*---------------------------------------------------------*/ +//.. /*--- ISEL: Integer expression auxiliaries ---*/ +//.. /*---------------------------------------------------------*/ +//.. +//.. /* --------------------- AMODEs --------------------- */ +//.. +//.. /* Return an AMode which computes the value of the specified +//.. expression, possibly also adding insns to the code list as a +//.. result. The expression may only be a 32-bit one. +//.. */ +//.. +//.. static Bool sane_AMode ( X86AMode* am ) +//.. { +//.. switch (am->tag) { +//.. case Xam_IR: +//.. return hregClass(am->Xam.IR.reg) == HRcInt32 +//.. && (hregIsVirtual(am->Xam.IR.reg) +//.. || am->Xam.IR.reg == hregX86_EBP()); +//.. case Xam_IRRS: +//.. return hregClass(am->Xam.IRRS.base) == HRcInt32 +//.. && hregIsVirtual(am->Xam.IRRS.base) +//.. && hregClass(am->Xam.IRRS.index) == HRcInt32 +//.. && hregIsVirtual(am->Xam.IRRS.index); +//.. default: +//.. vpanic("sane_AMode: unknown x86 amode tag"); +//.. } +//.. } +//.. +//.. static X86AMode* iselIntExpr_AMode ( ISelEnv* env, IRExpr* e ) +//.. { +//.. X86AMode* am = iselIntExpr_AMode_wrk(env, e); +//.. vassert(sane_AMode(am)); +//.. return am; +//.. } +//.. +//.. /* DO NOT CALL THIS DIRECTLY ! */ +//.. static X86AMode* iselIntExpr_AMode_wrk ( ISelEnv* env, IRExpr* e ) +//.. { +//.. IRType ty = typeOfIRExpr(env->type_env,e); +//.. vassert(ty == 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_U8) { +//.. UInt shift = e->Iex.Binop.arg2->Iex.Binop.arg2->Iex.Const.con->Ico.U8; +//.. if (shift == 1 || shift == 2 || shift == 3) { +//.. HReg r1 = iselIntExpr_R(env, e->Iex.Binop.arg1); +//.. HReg r2 = iselIntExpr_R(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 = iselIntExpr_R(env, e->Iex.Binop.arg1); +//.. return X86AMode_IR(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32, r1); +//.. } +//.. +//.. /* Doesn't match anything in particular. Generate it into +//.. a register and use that. */ +//.. { +//.. HReg r1 = iselIntExpr_R(env, e); +//.. return X86AMode_IR(0, r1); +//.. } +//.. } +//.. +//.. +//.. /* --------------------- RMIs --------------------- */ +//.. +//.. /* Similarly, calculate an expression into an X86RMI operand. As with +//.. iselIntExpr_R, the expression can have type 32, 16 or 8 bits. */ +//.. +//.. static X86RMI* iselIntExpr_RMI ( ISelEnv* env, IRExpr* e ) +//.. { +//.. X86RMI* rmi = iselIntExpr_RMI_wrk(env, e); +//.. /* sanity checks ... */ +//.. switch (rmi->tag) { +//.. case Xrmi_Imm: +//.. return rmi; +//.. case Xrmi_Reg: +//.. vassert(hregClass(rmi->Xrmi.Reg.reg) == HRcInt32); +//.. vassert(hregIsVirtual(rmi->Xrmi.Reg.reg)); +//.. return rmi; +//.. case Xrmi_Mem: +//.. vassert(sane_AMode(rmi->Xrmi.Mem.am)); +//.. return rmi; +//.. default: +//.. vpanic("iselIntExpr_RMI: unknown x86 RMI tag"); +//.. } +//.. } +//.. +//.. /* DO NOT CALL THIS DIRECTLY ! */ +//.. static X86RMI* iselIntExpr_RMI_wrk ( ISelEnv* env, IRExpr* e ) +//.. { +//.. IRType ty = typeOfIRExpr(env->type_env,e); +//.. vassert(ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8); +//.. +//.. /* special case: immediate */ +//.. if (e->tag == Iex_Const) { +//.. UInt u; +//.. switch (e->Iex.Const.con->tag) { +//.. case Ico_U32: u = e->Iex.Const.con->Ico.U32; break; +//.. case Ico_U16: u = 0xFFFF & (e->Iex.Const.con->Ico.U16); break; +//.. case Ico_U8: u = 0xFF & (e->Iex.Const.con->Ico.U8); break; +//.. default: vpanic("iselIntExpr_RMI.Iex_Const(x86h)"); +//.. } +//.. return X86RMI_Imm(u); +//.. } +//.. +//.. /* special case: 32-bit GET */ +//.. if (e->tag == Iex_Get && ty == Ity_I32) { +//.. return X86RMI_Mem(X86AMode_IR(e->Iex.Get.offset, +//.. hregX86_EBP())); +//.. } +//.. +//.. /* special case: load from memory */ +//.. +//.. /* default case: calculate into a register and return that */ +//.. { +//.. HReg r = iselIntExpr_R ( env, e ); +//.. return X86RMI_Reg(r); +//.. } +//.. } +//.. +//.. +//.. /* --------------------- RIs --------------------- */ +//.. +//.. /* Calculate an expression into an X86RI operand. As with +//.. iselIntExpr_R, the expression can have type 32, 16 or 8 bits. */ +//.. +//.. static X86RI* iselIntExpr_RI ( ISelEnv* env, IRExpr* e ) +//.. { +//.. X86RI* ri = iselIntExpr_RI_wrk(env, e); +//.. /* sanity checks ... */ +//.. switch (ri->tag) { +//.. case Xri_Imm: +//.. return ri; +//.. case Xrmi_Reg: +//.. vassert(hregClass(ri->Xri.Reg.reg) == HRcInt32); +//.. vassert(hregIsVirtual(ri->Xri.Reg.reg)); +//.. return ri; +//.. default: +//.. vpanic("iselIntExpr_RI: unknown x86 RI tag"); +//.. } +//.. } +//.. +//.. /* DO NOT CALL THIS DIRECTLY ! */ +//.. static X86RI* iselIntExpr_RI_wrk ( ISelEnv* env, IRExpr* e ) +//.. { +//.. IRType ty = typeOfIRExpr(env->type_env,e); +//.. vassert(ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8); +//.. +//.. /* special case: immediate */ +//.. if (e->tag == Iex_Const) { +//.. UInt u; +//.. switch (e->Iex.Const.con->tag) { +//.. case Ico_U32: u = e->Iex.Const.con->Ico.U32; break; +//.. case Ico_U16: u = 0xFFFF & (e->Iex.Const.con->Ico.U16); break; +//.. case Ico_U8: u = 0xFF & (e->Iex.Const.con->Ico.U8); break; +//.. default: vpanic("iselIntExpr_RMI.Iex_Const(x86h)"); +//.. } +//.. return X86RI_Imm(u); +//.. } +//.. +//.. /* default case: calculate into a register and return that */ +//.. { +//.. HReg r = iselIntExpr_R ( env, e ); +//.. return X86RI_Reg(r); +//.. } +//.. } +//.. +//.. +//.. /* --------------------- RMs --------------------- */ +//.. +//.. /* Similarly, calculate an expression into an X86RM operand. As with +//.. iselIntExpr_R, the expression can have type 32, 16 or 8 bits. */ +//.. +//.. static X86RM* iselIntExpr_RM ( ISelEnv* env, IRExpr* e ) +//.. { +//.. X86RM* rm = iselIntExpr_RM_wrk(env, e); +//.. /* sanity checks ... */ +//.. switch (rm->tag) { +//.. case Xrm_Reg: +//.. vassert(hregClass(rm->Xrm.Reg.reg) == HRcInt32); +//.. vassert(hregIsVirtual(rm->Xrm.Reg.reg)); +//.. return rm; +//.. case Xrm_Mem: +//.. vassert(sane_AMode(rm->Xrm.Mem.am)); +//.. return rm; +//.. default: +//.. vpanic("iselIntExpr_RM: unknown x86 RM tag"); +//.. } +//.. } +//.. +//.. /* DO NOT CALL THIS DIRECTLY ! */ +//.. static X86RM* iselIntExpr_RM_wrk ( ISelEnv* env, IRExpr* e ) +//.. { +//.. IRType ty = typeOfIRExpr(env->type_env,e); +//.. vassert(ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8); +//.. +//.. /* special case: 32-bit GET */ +//.. if (e->tag == Iex_Get && ty == Ity_I32) { +//.. return X86RM_Mem(X86AMode_IR(e->Iex.Get.offset, +//.. hregX86_EBP())); +//.. } +//.. +//.. /* special case: load from memory */ +//.. +//.. /* default case: calculate into a register and return that */ +//.. { +//.. HReg r = iselIntExpr_R ( env, e ); +//.. return X86RM_Reg(r); +//.. } +//.. } +//.. +//.. +//.. /* --------------------- CONDCODE --------------------- */ +//.. +//.. /* Generate code to evaluated a bit-typed expression, returning the +//.. condition code which would correspond when the expression would +//.. notionally have returned 1. */ +//.. +//.. static X86CondCode iselCondCode ( ISelEnv* env, IRExpr* e ) +//.. { +//.. /* Uh, there's nothing we can sanity check here, unfortunately. */ +//.. return iselCondCode_wrk(env,e); +//.. } +//.. +//.. /* DO NOT CALL THIS DIRECTLY ! */ +//.. static X86CondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e ) +//.. { +//.. MatchInfo mi; +//.. DECLARE_PATTERN(p_32to1); +//.. DECLARE_PATTERN(p_1Uto32_then_32to1); +//.. DECLARE_PATTERN(p_1Sto32_then_32to1); +//.. +//.. vassert(e); +//.. vassert(typeOfIRExpr(env->type_env,e) == Ity_I1); +//.. +//.. /* Constant 1:Bit */ +//.. if (e->tag == Iex_Const && e->Iex.Const.con->Ico.U1 == True) { +//.. HReg r; +//.. vassert(e->Iex.Const.con->tag == Ico_U1); +//.. r = newVRegI(env); +//.. addInstr(env, X86Instr_Alu32R(Xalu_MOV,X86RMI_Imm(0),r)); +//.. addInstr(env, X86Instr_Alu32R(Xalu_XOR,X86RMI_Reg(r),r)); +//.. return Xcc_Z; +//.. } +//.. +//.. /* Not1(...) */ +//.. if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_Not1) { +//.. /* Generate code for the arg, and negate the test condition */ +//.. return 1 ^ iselCondCode(env, e->Iex.Unop.arg); +//.. } +//.. +//.. /* 32to1(1Uto32(expr1)) -- the casts are pointless, ignore them */ +//.. DEFINE_PATTERN(p_1Uto32_then_32to1, +//.. unop(Iop_32to1,unop(Iop_1Uto32,bind(0)))); +//.. if (matchIRExpr(&mi,p_1Uto32_then_32to1,e)) { +//.. IRExpr* expr1 = mi.bindee[0]; +//.. return iselCondCode(env, expr1); +//.. } +//.. +//.. /* 32to1(1Sto32(expr1)) -- the casts are pointless, ignore them */ +//.. DEFINE_PATTERN(p_1Sto32_then_32to1, +//.. unop(Iop_32to1,unop(Iop_1Sto32,bind(0)))); +//.. if (matchIRExpr(&mi,p_1Sto32_then_32to1,e)) { +//.. IRExpr* expr1 = mi.bindee[0]; +//.. return iselCondCode(env, expr1); +//.. } +//.. +//.. /* pattern: 32to1(expr32) */ +//.. DEFINE_PATTERN(p_32to1, +//.. unop(Iop_32to1,bind(0)) +//.. ); +//.. if (matchIRExpr(&mi,p_32to1,e)) { +//.. X86RM* rm = iselIntExpr_RM(env, mi.bindee[0]); +//.. addInstr(env, X86Instr_Test32(X86RI_Imm(1),rm)); +//.. return Xcc_NZ; +//.. } +//.. +//.. /* CmpEQ8 / CmpNE8 */ +//.. if (e->tag == Iex_Binop +//.. && (e->Iex.Binop.op == Iop_CmpEQ8 +//.. || e->Iex.Binop.op == Iop_CmpNE8)) { +//.. HReg r1 = iselIntExpr_R(env, e->Iex.Binop.arg1); +//.. X86RMI* rmi2 = iselIntExpr_RMI(env, e->Iex.Binop.arg2); +//.. HReg r = newVRegI(env); +//.. addInstr(env, mk_iMOVsd_RR(r1,r)); +//.. addInstr(env, X86Instr_Alu32R(Xalu_XOR,rmi2,r)); +//.. addInstr(env, X86Instr_Alu32R(Xalu_AND,X86RMI_Imm(0xFF),r)); +//.. switch (e->Iex.Binop.op) { +//.. case Iop_CmpEQ8: return Xcc_Z; +//.. case Iop_CmpNE8: return Xcc_NZ; +//.. default: vpanic("iselCondCode(x86): CmpXX8"); +//.. } +//.. } +//.. +//.. /* CmpEQ16 / CmpNE16 */ +//.. if (e->tag == Iex_Binop +//.. && (e->Iex.Binop.op == Iop_CmpEQ16 +//.. || e->Iex.Binop.op == Iop_CmpNE16)) { +//.. HReg r1 = iselIntExpr_R(env, e->Iex.Binop.arg1); +//.. X86RMI* rmi2 = iselIntExpr_RMI(env, e->Iex.Binop.arg2); +//.. HReg r = newVRegI(env); +//.. addInstr(env, mk_iMOVsd_RR(r1,r)); +//.. addInstr(env, X86Instr_Alu32R(Xalu_XOR,rmi2,r)); +//.. addInstr(env, X86Instr_Alu32R(Xalu_AND,X86RMI_Imm(0xFFFF),r)); +//.. switch (e->Iex.Binop.op) { +//.. case Iop_CmpEQ16: return Xcc_Z; +//.. case Iop_CmpNE16: return Xcc_NZ; +//.. default: vpanic("iselCondCode(x86): CmpXX16"); +//.. } +//.. } +//.. +//.. /* CmpNE32(1Sto32(b), 0) ==> b */ +//.. { +//.. DECLARE_PATTERN(p_CmpNE32_1Sto32); +//.. DEFINE_PATTERN( +//.. p_CmpNE32_1Sto32, +//.. binop(Iop_CmpNE32, unop(Iop_1Sto32,bind(0)), mkU32(0))); +//.. if (matchIRExpr(&mi, p_CmpNE32_1Sto32, e)) { +//.. return iselCondCode(env, mi.bindee[0]); +//.. } +//.. } +//.. +//.. /* Cmp*32*(x,y) */ +//.. if (e->tag == Iex_Binop +//.. && (e->Iex.Binop.op == Iop_CmpEQ32 +//.. || e->Iex.Binop.op == Iop_CmpNE32 +//.. || e->Iex.Binop.op == Iop_CmpLT32S +//.. || e->Iex.Binop.op == Iop_CmpLT32U +//.. || e->Iex.Binop.op == Iop_CmpLE32S +//.. || e->Iex.Binop.op == Iop_CmpLE32U)) { +//.. HReg r1 = iselIntExpr_R(env, e->Iex.Binop.arg1); +//.. X86RMI* rmi2 = iselIntExpr_RMI(env, e->Iex.Binop.arg2); +//.. addInstr(env, X86Instr_Alu32R(Xalu_CMP,rmi2,r1)); +//.. switch (e->Iex.Binop.op) { +//.. case Iop_CmpEQ32: return Xcc_Z; +//.. case Iop_CmpNE32: return Xcc_NZ; +//.. case Iop_CmpLT32S: return Xcc_L; +//.. case Iop_CmpLT32U: return Xcc_B; +//.. case Iop_CmpLE32S: return Xcc_LE; +//.. case Iop_CmpLE32U: return Xcc_BE; +//.. default: vpanic("iselCondCode(x86): CmpXX32"); +//.. } +//.. } +//.. +//.. /* CmpNE64(1Sto64(b), 0) ==> b */ +//.. { +//.. DECLARE_PATTERN(p_CmpNE64_1Sto64); +//.. DEFINE_PATTERN( +//.. p_CmpNE64_1Sto64, +//.. binop(Iop_CmpNE64, unop(Iop_1Sto64,bind(0)), mkU64(0))); +//.. if (matchIRExpr(&mi, p_CmpNE64_1Sto64, e)) { +//.. return iselCondCode(env, mi.bindee[0]); +//.. } +//.. } +//.. +//.. /* CmpNE64(x, 0) */ +//.. { +//.. DECLARE_PATTERN(p_CmpNE64_x_zero); +//.. DEFINE_PATTERN( +//.. p_CmpNE64_x_zero, +//.. binop(Iop_CmpNE64, bind(0), mkU64(0)) ); +//.. if (matchIRExpr(&mi, p_CmpNE64_x_zero, e)) { +//.. HReg hi, lo; +//.. IRExpr* x = mi.bindee[0]; +//.. HReg tmp = newVRegI(env); +//.. iselInt64Expr( &hi, &lo, env, x ); +//.. addInstr(env, mk_iMOVsd_RR(hi, tmp)); +//.. addInstr(env, X86Instr_Alu32R(Xalu_OR,X86RMI_Reg(lo), tmp)); +//.. return Xcc_NZ; +//.. } +//.. } +//.. +//.. /* CmpNE64 */ +//.. if (e->tag == Iex_Binop +//.. && e->Iex.Binop.op == Iop_CmpNE64) { +//.. HReg hi1, hi2, lo1, lo2; +//.. HReg tHi = newVRegI(env); +//.. HReg tLo = newVRegI(env); +//.. iselInt64Expr( &hi1, &lo1, env, e->Iex.Binop.arg1 ); +//.. iselInt64Expr( &hi2, &lo2, env, e->Iex.Binop.arg2 ); +//.. addInstr(env, mk_iMOVsd_RR(hi1, tHi)); +//.. addInstr(env, X86Instr_Alu32R(Xalu_XOR,X86RMI_Reg(hi2), tHi)); +//.. addInstr(env, mk_iMOVsd_RR(lo1, tLo)); +//.. addInstr(env, X86Instr_Alu32R(Xalu_XOR,X86RMI_Reg(lo2), tLo)); +//.. addInstr(env, X86Instr_Alu32R(Xalu_OR,X86RMI_Reg(tHi), tLo)); +//.. switch (e->Iex.Binop.op) { +//.. case Iop_CmpNE64: return Xcc_NZ; +//.. default: vpanic("iselCondCode(x86): CmpXX64"); +//.. } +//.. } +//.. +//.. /* var */ +//.. if (e->tag == Iex_Tmp) { +//.. HReg r32 = lookupIRTemp(env, e->Iex.Tmp.tmp); +//.. HReg dst = newVRegI(env); +//.. addInstr(env, mk_iMOVsd_RR(r32,dst)); +//.. addInstr(env, X86Instr_Alu32R(Xalu_AND,X86RMI_Imm(1),dst)); +//.. return Xcc_NZ; +//.. } +//.. +//.. ppIRExpr(e); +//.. vpanic("iselCondCode"); +//.. } +//.. +//.. +//.. /*---------------------------------------------------------*/ +//.. /*--- ISEL: Integer expressions (64 bit) ---*/ +//.. /*---------------------------------------------------------*/ +//.. +//.. /* Compute a 64-bit value into a register pair, which is returned as +//.. the first two parameters. As with iselIntExpr_R, these may be +//.. either real or virtual regs; in any case they must not be changed +//.. by subsequent code emitted by the caller. */ +//.. +//.. static void iselInt64Expr ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e ) +//.. { +//.. iselInt64Expr_wrk(rHi, rLo, env, e); +//.. # if 0 +//.. vex_printf("\n"); ppIRExpr(e); vex_printf("\n"); +//.. # endif +//.. vassert(hregClass(*rHi) == HRcInt32); +//.. vassert(hregIsVirtual(*rHi)); +//.. vassert(hregClass(*rLo) == HRcInt32); +//.. vassert(hregIsVirtual(*rLo)); +//.. } +//.. +//.. /* DO NOT CALL THIS DIRECTLY ! */ +//.. static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e ) +//.. { +//.. HWord fn = 0; /* helper fn for most SIMD64 stuff */ +//.. vassert(e); +//.. vassert(typeOfIRExpr(env->type_env,e) == Ity_I64); +//.. +//.. /* 64-bit literal */ +//.. if (e->tag == Iex_Const) { +//.. ULong w64 = e->Iex.Const.con->Ico.U64; +//.. UInt wHi = ((UInt)(w64 >> 32)) & 0xFFFFFFFF; +//.. UInt wLo = ((UInt)w64) & 0xFFFFFFFF; +//.. HReg tLo = newVRegI(env); +//.. HReg tHi = newVRegI(env); +//.. vassert(e->Iex.Const.con->tag == Ico_U64); +//.. addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(wHi), tHi)); +//.. addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(wLo), tLo)); +//.. *rHi = tHi; +//.. *rLo = tLo; +//.. return; +//.. } +//.. +//.. /* read 64-bit IRTemp */ +//.. if (e->tag == Iex_Tmp) { +//.. lookupIRTemp64( rHi, rLo, env, e->Iex.Tmp.tmp); +//.. return; +//.. } +//.. +//.. /* 64-bit load */ +//.. if (e->tag == Iex_LDle) { +//.. HReg tLo, tHi; +//.. X86AMode *am0, *am4; +//.. vassert(e->Iex.LDle.ty == Ity_I64); +//.. tLo = newVRegI(env); +//.. tHi = newVRegI(env); +//.. am0 = iselIntExpr_AMode(env, e->Iex.LDle.addr); +//.. am4 = advance4(am0); +//.. addInstr(env, X86Instr_Alu32R( Xalu_MOV, X86RMI_Mem(am0), tLo )); +//.. addInstr(env, X86Instr_Alu32R( Xalu_MOV, X86RMI_Mem(am4), tHi )); +//.. *rHi = tHi; +//.. *rLo = tLo; +//.. return; +//.. } +//.. +//.. /* 64-bit GET */ +//.. if (e->tag == Iex_Get) { +//.. X86AMode* am = X86AMode_IR(e->Iex.Get.offset, hregX86_EBP()); +//.. X86AMode* am4 = advance4(am); +//.. HReg tLo = newVRegI(env); +//.. HReg tHi = newVRegI(env); +//.. addInstr(env, X86Instr_Alu32R( Xalu_MOV, X86RMI_Mem(am), tLo )); +//.. addInstr(env, X86Instr_Alu32R( Xalu_MOV, X86RMI_Mem(am4), tHi )); +//.. *rHi = tHi; +//.. *rLo = tLo; +//.. return; +//.. } +//.. +//.. /* 64-bit GETI */ +//.. if (e->tag == Iex_GetI) { +//.. X86AMode* am +//.. = genGuestArrayOffset( env, e->Iex.GetI.descr, +//.. e->Iex.GetI.ix, e->Iex.GetI.bias ); +//.. X86AMode* am4 = advance4(am); +//.. HReg tLo = newVRegI(env); +//.. HReg tHi = newVRegI(env); +//.. addInstr(env, X86Instr_Alu32R( Xalu_MOV, X86RMI_Mem(am), tLo )); +//.. addInstr(env, X86Instr_Alu32R( Xalu_MOV, X86RMI_Mem(am4), tHi )); +//.. *rHi = tHi; +//.. *rLo = tLo; +//.. return; +//.. } +//.. +//.. /* 64-bit Mux0X */ +//.. if (e->tag == Iex_Mux0X) { +//.. HReg e0Lo, e0Hi, eXLo, eXHi, r8; +//.. HReg tLo = newVRegI(env); +//.. HReg tHi = newVRegI(env); +//.. iselInt64Expr(&e0Hi, &e0Lo, env, e->Iex.Mux0X.expr0); +//.. iselInt64Expr(&eXHi, &eXLo, env, e->Iex.Mux0X.exprX); +//.. addInstr(env, mk_iMOVsd_RR(eXHi, tHi)); +//.. addInstr(env, mk_iMOVsd_RR(eXLo, tLo)); +//.. r8 = iselIntExpr_R(env, e->Iex.Mux0X.cond); +//.. addInstr(env, X86Instr_Test32(X86RI_Imm(0xFF), X86RM_Reg(r8))); +//.. /* This assumes the first cmov32 doesn't trash the condition +//.. codes, so they are still available for the second cmov32 */ +//.. addInstr(env, X86Instr_CMov32(Xcc_Z,X86RM_Reg(e0Hi),tHi)); +//.. addInstr(env, X86Instr_CMov32(Xcc_Z,X86RM_Reg(e0Lo),tLo)); +//.. *rHi = tHi; +//.. *rLo = tLo; +//.. return; +//.. } +//.. +//.. /* --------- BINARY ops --------- */ +//.. if (e->tag == Iex_Binop) { +//.. switch (e->Iex.Binop.op) { +//.. /* 32 x 32 -> 64 multiply */ +//.. case Iop_MullU32: +//.. case Iop_MullS32: { +//.. /* get one operand into %eax, and the other into a R/M. +//.. Need to make an educated guess about which is better in +//.. which. */ +//.. HReg tLo = newVRegI(env); +//.. HReg tHi = newVRegI(env); +//.. Bool syned = e->Iex.Binop.op == Iop_MullS32; +//.. X86RM* rmLeft = iselIntExpr_RM(env, e->Iex.Binop.arg1); +//.. HReg rRight = iselIntExpr_R(env, e->Iex.Binop.arg2); +//.. addInstr(env, mk_iMOVsd_RR(rRight, hregX86_EAX())); +//.. addInstr(env, X86Instr_MulL(syned, Xss_32, rmLeft)); +//.. /* Result is now in EDX:EAX. Tell the caller. */ +//.. addInstr(env, mk_iMOVsd_RR(hregX86_EDX(), tHi)); +//.. addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), tLo)); +//.. *rHi = tHi; +//.. *rLo = tLo; +//.. return; +//.. } +//.. +//.. /* 64 x 32 -> (32(rem),32(div)) division */ +//.. case Iop_DivModU64to32: +//.. case Iop_DivModS64to32: { +//.. /* Get the 64-bit operand into edx:eax, and the other into +//.. any old R/M. */ +//.. HReg sHi, sLo; +//.. HReg tLo = newVRegI(env); +//.. HReg tHi = newVRegI(env); +//.. Bool syned = e->Iex.Binop.op == Iop_DivModS64to32; +//.. X86RM* rmRight = iselIntExpr_RM(env, e->Iex.Binop.arg2); +//.. iselInt64Expr(&sHi,&sLo, env, e->Iex.Binop.arg1); +//.. addInstr(env, mk_iMOVsd_RR(sHi, hregX86_EDX())); +//.. addInstr(env, mk_iMOVsd_RR(sLo, hregX86_EAX())); +//.. addInstr(env, X86Instr_Div(syned, Xss_32, rmRight)); +//.. addInstr(env, mk_iMOVsd_RR(hregX86_EDX(), tHi)); +//.. addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), tLo)); +//.. *rHi = tHi; +//.. *rLo = tLo; +//.. return; +//.. } +//.. +//.. /* Or64/And64/Xor64 */ +//.. case Iop_Or64: +//.. case Iop_And64: +//.. case Iop_Xor64: { +//.. HReg xLo, xHi, yLo, yHi; +//.. HReg tLo = newVRegI(env); +//.. HReg tHi = newVRegI(env); +//.. X86AluOp op = e->Iex.Binop.op==Iop_Or64 ? Xalu_OR +//.. : e->Iex.Binop.op==Iop_And64 ? Xalu_AND +//.. : Xalu_XOR; +//.. iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1); +//.. addInstr(env, mk_iMOVsd_RR(xHi, tHi)); +//.. addInstr(env, mk_iMOVsd_RR(xLo, tLo)); +//.. iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2); +//.. addInstr(env, X86Instr_Alu32R(op, X86RMI_Reg(yHi), tHi)); +//.. addInstr(env, X86Instr_Alu32R(op, X86RMI_Reg(yLo), tLo)); +//.. *rHi = tHi; +//.. *rLo = tLo; +//.. return; +//.. } +//.. +//.. /* Add64/Sub64 */ +//.. case Iop_Add64: +//.. case Iop_Sub64: { +//.. HReg xLo, xHi, yLo, yHi; +//.. HReg tLo = newVRegI(env); +//.. HReg tHi = newVRegI(env); +//.. iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1); +//.. addInstr(env, mk_iMOVsd_RR(xHi, tHi)); +//.. addInstr(env, mk_iMOVsd_RR(xLo, tLo)); +//.. iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2); +//.. if (e->Iex.Binop.op==Iop_Add64) { +//.. addInstr(env, X86Instr_Alu32R(Xalu_ADD, X86RMI_Reg(yLo), tLo)); +//.. addInstr(env, X86Instr_Alu32R(Xalu_ADC, X86RMI_Reg(yHi), tHi)); +//.. } else { +//.. addInstr(env, X86Instr_Alu32R(Xalu_SUB, X86RMI_Reg(yLo), tLo)); +//.. addInstr(env, X86Instr_Alu32R(Xalu_SBB, X86RMI_Reg(yHi), tHi)); +//.. } +//.. *rHi = tHi; +//.. *rLo = tLo; +//.. return; +//.. } +//.. +//.. /* 32HLto64(e1,e2) */ +//.. case Iop_32HLto64: +//.. *rHi = iselIntExpr_R(env, e->Iex.Binop.arg1); +//.. *rLo = iselIntExpr_R(env, e->Iex.Binop.arg2); +//.. return; +//.. +//.. /* 64-bit shifts */ +//.. case Iop_Shl64: { +//.. /* We use the same ingenious scheme as gcc. Put the value +//.. to be shifted into %hi:%lo, and the shift amount into +//.. %cl. Then (dsts on right, a la ATT syntax): +//.. +//.. shldl %cl, %lo, %hi -- make %hi be right for the +//.. -- shift amt %cl % 32 +//.. shll %cl, %lo -- make %lo be right for the +//.. -- shift amt %cl % 32 +//.. +//.. Now, if (shift amount % 64) is in the range 32 .. 63, +//.. we have to do a fixup, which puts the result low half +//.. into the result high half, and zeroes the low half: +//.. +//.. testl $32, %ecx +//.. +//.. cmovnz %lo, %hi +//.. movl $0, %tmp -- sigh; need yet another reg +//.. cmovnz %tmp, %lo +//.. */ +//.. HReg rAmt, sHi, sLo, tHi, tLo, tTemp; +//.. tLo = newVRegI(env); +//.. tHi = newVRegI(env); +//.. tTemp = newVRegI(env); +//.. rAmt = iselIntExpr_R(env, e->Iex.Binop.arg2); +//.. iselInt64Expr(&sHi,&sLo, env, e->Iex.Binop.arg1); +//.. addInstr(env, mk_iMOVsd_RR(rAmt, hregX86_ECX())); +//.. addInstr(env, mk_iMOVsd_RR(sHi, tHi)); +//.. addInstr(env, mk_iMOVsd_RR(sLo, tLo)); +//.. /* Ok. Now shift amt is in %ecx, and value is in tHi/tLo +//.. and those regs are legitimately modifiable. */ +//.. addInstr(env, X86Instr_Sh3232(Xsh_SHL, 0/*%cl*/, tLo, tHi)); +//.. addInstr(env, X86Instr_Sh32(Xsh_SHL, 0/*%cl*/, X86RM_Reg(tLo))); +//.. addInstr(env, X86Instr_Test32(X86RI_Imm(32), +//.. X86RM_Reg(hregX86_ECX()))); +//.. addInstr(env, X86Instr_CMov32(Xcc_NZ, X86RM_Reg(tLo), tHi)); +//.. addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(0), tTemp)); +//.. addInstr(env, X86Instr_CMov32(Xcc_NZ, X86RM_Reg(tTemp), tLo)); +//.. *rHi = tHi; +//.. *rLo = tLo; +//.. return; +//.. } +//.. +//.. case Iop_Shr64: { +//.. /* We use the same ingenious scheme as gcc. Put the value +//.. to be shifted into %hi:%lo, and the shift amount into +//.. %cl. Then: +//.. +//.. shrdl %cl, %hi, %lo -- make %lo be right for the +//.. -- shift amt %cl % 32 +//.. shrl %cl, %hi -- make %hi be right for the +//.. -- shift amt %cl % 32 +//.. +//.. Now, if (shift amount % 64) is in the range 32 .. 63, +//.. we have to do a fixup, which puts the result high half +//.. into the result low half, and zeroes the high half: +//.. +//.. testl $32, %ecx +//.. +//.. cmovnz %hi, %lo +//.. movl $0, %tmp -- sigh; need yet another reg +//.. cmovnz %tmp, %hi +//.. */ +//.. HReg rAmt, sHi, sLo, tHi, tLo, tTemp; +//.. tLo = newVRegI(env); +//.. tHi = newVRegI(env); +//.. tTemp = newVRegI(env); +//.. rAmt = iselIntExpr_R(env, e->Iex.Binop.arg2); +//.. iselInt64Expr(&sHi,&sLo, env, e->Iex.Binop.arg1); +//.. addInstr(env, mk_iMOVsd_RR(rAmt, hregX86_ECX())); +//.. addInstr(env, mk_iMOVsd_RR(sHi, tHi)); +//.. addInstr(env, mk_iMOVsd_RR(sLo, tLo)); +//.. /* Ok. Now shift amt is in %ecx, and value is in tHi/tLo +//.. and those regs are legitimately modifiable. */ +//.. addInstr(env, X86Instr_Sh3232(Xsh_SHR, 0/*%cl*/, tHi, tLo)); +//.. addInstr(env, X86Instr_Sh32(Xsh_SHR, 0/*%cl*/, X86RM_Reg(tHi))); +//.. addInstr(env, X86Instr_Test32(X86RI_Imm(32), +//.. X86RM_Reg(hregX86_ECX()))); +//.. addInstr(env, X86Instr_CMov32(Xcc_NZ, X86RM_Reg(tHi), tLo)); +//.. addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(0), tTemp)); +//.. addInstr(env, X86Instr_CMov32(Xcc_NZ, X86RM_Reg(tTemp), tHi)); +//.. *rHi = tHi; +//.. *rLo = tLo; +//.. return; +//.. } +//.. +//.. /* F64 -> I64 */ +//.. /* Sigh, this is an almost exact copy of the F64 -> I32/I16 +//.. case. Unfortunately I see no easy way to avoid the +//.. duplication. */ +//.. case Iop_F64toI64: { +//.. HReg rf = iselDblExpr(env, e->Iex.Binop.arg2); +//.. HReg tLo = newVRegI(env); +//.. HReg tHi = newVRegI(env); +//.. +//.. /* Used several times ... */ +//.. /* Careful ... this sharing is only safe because +//.. zero_esp/four_esp do not hold any registers which the +//.. register allocator could attempt to swizzle later. */ +//.. X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP()); +//.. X86AMode* four_esp = X86AMode_IR(4, hregX86_ESP()); +//.. +//.. /* rf now holds the value to be converted, and rrm holds +//.. the rounding mode value, encoded as per the +//.. IRRoundingMode enum. The first thing to do is set the +//.. FPU's rounding mode accordingly. */ +//.. +//.. /* Create a space for the format conversion. */ +//.. /* subl $8, %esp */ +//.. sub_from_esp(env, 8); +//.. +//.. /* Set host rounding mode */ +//.. set_FPU_rounding_mode( env, e->Iex.Binop.arg1 ); +//.. +//.. /* gistll %rf, 0(%esp) */ +//.. addInstr(env, X86Instr_FpLdStI(False/*store*/, 8, rf, zero_esp)); +//.. +//.. /* movl 0(%esp), %dstLo */ +//.. /* movl 4(%esp), %dstHi */ +//.. addInstr(env, X86Instr_Alu32R( +//.. Xalu_MOV, X86RMI_Mem(zero_esp), tLo)); +//.. addInstr(env, X86Instr_Alu32R( +//.. Xalu_MOV, X86RMI_Mem(four_esp), tHi)); +//.. +//.. /* Restore default FPU rounding. */ +//.. set_FPU_rounding_default( env ); +//.. +//.. /* addl $8, %esp */ +//.. add_to_esp(env, 8); +//.. +//.. *rHi = tHi; +//.. *rLo = tLo; +//.. return; +//.. } +//.. +//.. case Iop_Add8x8: +//.. fn = (HWord)h_generic_calc_Add8x8; goto binnish; +//.. case Iop_Add16x4: +//.. fn = (HWord)h_generic_calc_Add16x4; goto binnish; +//.. case Iop_Add32x2: +//.. fn = (HWord)h_generic_calc_Add32x2; goto binnish; +//.. +//.. case Iop_Avg8Ux8: +//.. fn = (HWord)h_generic_calc_Avg8Ux8; goto binnish; +//.. case Iop_Avg16Ux4: +//.. fn = (HWord)h_generic_calc_Avg16Ux4; goto binnish; +//.. +//.. case Iop_CmpEQ8x8: +//.. fn = (HWord)h_generic_calc_CmpEQ8x8; goto binnish; +//.. case Iop_CmpEQ16x4: +//.. fn = (HWord)h_generic_calc_CmpEQ16x4; goto binnish; +//.. case Iop_CmpEQ32x2: +//.. fn = (HWord)h_generic_calc_CmpEQ32x2; goto binnish; +//.. +//.. case Iop_CmpGT8Sx8: +//.. fn = (HWord)h_generic_calc_CmpGT8Sx8; goto binnish; +//.. case Iop_CmpGT16Sx4: +//.. fn = (HWord)h_generic_calc_CmpGT16Sx4; goto binnish; +//.. case Iop_CmpGT32Sx2: +//.. fn = (HWord)h_generic_calc_CmpGT32Sx2; goto binnish; +//.. +//.. case Iop_InterleaveHI8x8: +//.. fn = (HWord)h_generic_calc_InterleaveHI8x8; goto binnish; +//.. case Iop_InterleaveLO8x8: +//.. fn = (HWord)h_generic_calc_InterleaveLO8x8; goto binnish; +//.. case Iop_InterleaveHI16x4: +//.. fn = (HWord)h_generic_calc_InterleaveHI16x4; goto binnish; +//.. case Iop_InterleaveLO16x4: +//.. fn = (HWord)h_generic_calc_InterleaveLO16x4; goto binnish; +//.. case Iop_InterleaveHI32x2: +//.. fn = (HWord)h_generic_calc_InterleaveHI32x2; goto binnish; +//.. case Iop_InterleaveLO32x2: +//.. fn = (HWord)h_generic_calc_InterleaveLO32x2; goto binnish; +//.. +//.. case Iop_Max8Ux8: +//.. fn = (HWord)h_generic_calc_Max8Ux8; goto binnish; +//.. case Iop_Max16Sx4: +//.. fn = (HWord)h_generic_calc_Max16Sx4; goto binnish; +//.. case Iop_Min8Ux8: +//.. fn = (HWord)h_generic_calc_Min8Ux8; goto binnish; +//.. case Iop_Min16Sx4: +//.. fn = (HWord)h_generic_calc_Min16Sx4; goto binnish; +//.. +//.. case Iop_Mul16x4: +//.. fn = (HWord)h_generic_calc_Mul16x4; goto binnish; +//.. case Iop_MulHi16Sx4: +//.. fn = (HWord)h_generic_calc_MulHi16Sx4; goto binnish; +//.. case Iop_MulHi16Ux4: +//.. fn = (HWord)h_generic_calc_MulHi16Ux4; goto binnish; +//.. +//.. case Iop_QAdd8Sx8: +//.. fn = (HWord)h_generic_calc_QAdd8Sx8; goto binnish; +//.. case Iop_QAdd16Sx4: +//.. fn = (HWord)h_generic_calc_QAdd16Sx4; goto binnish; +//.. case Iop_QAdd8Ux8: +//.. fn = (HWord)h_generic_calc_QAdd8Ux8; goto binnish; +//.. case Iop_QAdd16Ux4: +//.. fn = (HWord)h_generic_calc_QAdd16Ux4; goto binnish; +//.. +//.. case Iop_QNarrow32Sx2: +//.. fn = (HWord)h_generic_calc_QNarrow32Sx2; goto binnish; +//.. case Iop_QNarrow16Sx4: +//.. fn = (HWord)h_generic_calc_QNarrow16Sx4; goto binnish; +//.. case Iop_QNarrow16Ux4: +//.. fn = (HWord)h_generic_calc_QNarrow16Ux4; goto binnish; +//.. +//.. case Iop_QSub8Sx8: +//.. fn = (HWord)h_generic_calc_QSub8Sx8; goto binnish; +//.. case Iop_QSub16Sx4: +//.. fn = (HWord)h_generic_calc_QSub16Sx4; goto binnish; +//.. case Iop_QSub8Ux8: +//.. fn = (HWord)h_generic_calc_QSub8Ux8; goto binnish; +//.. case Iop_QSub16Ux4: +//.. fn = (HWord)h_generic_calc_QSub16Ux4; goto binnish; +//.. +//.. case Iop_Sub8x8: +//.. fn = (HWord)h_generic_calc_Sub8x8; goto binnish; +//.. case Iop_Sub16x4: +//.. fn = (HWord)h_generic_calc_Sub16x4; goto binnish; +//.. case Iop_Sub32x2: +//.. fn = (HWord)h_generic_calc_Sub32x2; goto binnish; +//.. +//.. binnish: { +//.. /* Note: the following assumes all helpers are of +//.. signature +//.. ULong fn ( ULong, ULong ), and they are +//.. not marked as regparm functions. +//.. */ +//.. HReg xLo, xHi, yLo, yHi; +//.. HReg tLo = newVRegI(env); +//.. HReg tHi = newVRegI(env); +//.. iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2); +//.. addInstr(env, X86Instr_Push(X86RMI_Reg(yHi))); +//.. addInstr(env, X86Instr_Push(X86RMI_Reg(yLo))); +//.. iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1); +//.. addInstr(env, X86Instr_Push(X86RMI_Reg(xHi))); +//.. addInstr(env, X86Instr_Push(X86RMI_Reg(xLo))); +//.. addInstr(env, X86Instr_Call( Xcc_ALWAYS, (UInt)fn, 0 )); +//.. add_to_esp(env, 4*4); +//.. addInstr(env, mk_iMOVsd_RR(hregX86_EDX(), tHi)); +//.. addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), tLo)); +//.. *rHi = tHi; +//.. *rLo = tLo; +//.. return; +//.. } +//.. +//.. case Iop_ShlN32x2: +//.. fn = (HWord)h_generic_calc_ShlN32x2; goto shifty; +//.. case Iop_ShlN16x4: +//.. fn = (HWord)h_generic_calc_ShlN16x4; goto shifty; +//.. case Iop_ShrN32x2: +//.. fn = (HWord)h_generic_calc_ShrN32x2; goto shifty; +//.. case Iop_ShrN16x4: +//.. fn = (HWord)h_generic_calc_ShrN16x4; goto shifty; +//.. case Iop_SarN32x2: +//.. fn = (HWord)h_generic_calc_SarN32x2; goto shifty; +//.. case Iop_SarN16x4: +//.. fn = (HWord)h_generic_calc_SarN16x4; goto shifty; +//.. shifty: { +//.. /* Note: the following assumes all helpers are of +//.. signature +//.. ULong fn ( ULong, UInt ), and they are +//.. not marked as regparm functions. +//.. */ +//.. HReg xLo, xHi; +//.. HReg tLo = newVRegI(env); +//.. HReg tHi = newVRegI(env); +//.. X86RMI* y = iselIntExpr_RMI(env, e->Iex.Binop.arg2); +//.. addInstr(env, X86Instr_Push(y)); +//.. iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1); +//.. addInstr(env, X86Instr_Push(X86RMI_Reg(xHi))); +//.. addInstr(env, X86Instr_Push(X86RMI_Reg(xLo))); +//.. addInstr(env, X86Instr_Call( Xcc_ALWAYS, (UInt)fn, 0 )); +//.. add_to_esp(env, 3*4); +//.. addInstr(env, mk_iMOVsd_RR(hregX86_EDX(), tHi)); +//.. addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), tLo)); +//.. *rHi = tHi; +//.. *rLo = tLo; +//.. return; +//.. } +//.. +//.. default: +//.. break; +//.. } +//.. } /* if (e->tag == Iex_Binop) */ +//.. +//.. +//.. /* --------- UNARY ops --------- */ +//.. if (e->tag == Iex_Unop) { +//.. switch (e->Iex.Unop.op) { +//.. +//.. /* 32Sto64(e) */ +//.. case Iop_32Sto64: { +//.. HReg tLo = newVRegI(env); +//.. HReg tHi = newVRegI(env); +//.. HReg src = iselIntExpr_R(env, e->Iex.Unop.arg); +//.. addInstr(env, mk_iMOVsd_RR(src,tHi)); +//.. addInstr(env, mk_iMOVsd_RR(src,tLo)); +//.. addInstr(env, X86Instr_Sh32(Xsh_SAR, 31, X86RM_Reg(tHi))); +//.. *rHi = tHi; +//.. *rLo = tLo; +//.. return; +//.. } +//.. +//.. /* 32Uto64(e) */ +//.. case Iop_32Uto64: { +//.. HReg tLo = newVRegI(env); +//.. HReg tHi = newVRegI(env); +//.. HReg src = iselIntExpr_R(env, e->Iex.Unop.arg); +//.. addInstr(env, mk_iMOVsd_RR(src,tLo)); +//.. addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(0), tHi)); +//.. *rHi = tHi; +//.. *rLo = tLo; +//.. return; +//.. } +//.. +//.. /* 128{HI}to64 */ +//.. case Iop_128HIto64: +//.. case Iop_128to64: { +//.. Int off = e->Iex.Unop.op==Iop_128HIto64 ? 8 : 0; +//.. HReg tLo = newVRegI(env); +//.. HReg tHi = newVRegI(env); +//.. HReg vec = iselVecExpr(env, e->Iex.Unop.arg); +//.. X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP()); +//.. X86AMode* espLO = X86AMode_IR(off, hregX86_ESP()); +//.. X86AMode* espHI = X86AMode_IR(off+4, hregX86_ESP()); +//.. sub_from_esp(env, 16); +//.. addInstr(env, X86Instr_SseLdSt(False/*store*/, vec, esp0)); +//.. addInstr(env, X86Instr_Alu32R( Xalu_MOV, +//.. X86RMI_Mem(espLO), tLo )); +//.. addInstr(env, X86Instr_Alu32R( Xalu_MOV, +//.. X86RMI_Mem(espHI), tHi )); +//.. add_to_esp(env, 16); +//.. *rHi = tHi; +//.. *rLo = tLo; +//.. return; +//.. } +//.. +//.. /* could do better than this, but for now ... */ +//.. case Iop_1Sto64: { +//.. HReg tLo = newVRegI(env); +//.. HReg tHi = newVRegI(env); +//.. X86CondCode cond = iselCondCode(env, e->Iex.Unop.arg); +//.. addInstr(env, X86Instr_Set32(cond,tLo)); +//.. addInstr(env, X86Instr_Sh32(Xsh_SHL, 31, X86RM_Reg(tLo))); +//.. addInstr(env, X86Instr_Sh32(Xsh_SAR, 31, X86RM_Reg(tLo))); +//.. addInstr(env, mk_iMOVsd_RR(tLo, tHi)); +//.. *rHi = tHi; +//.. *rLo = tLo; +//.. return; +//.. } +//.. +//.. /* Not64(e) */ +//.. case Iop_Not64: { +//.. HReg tLo = newVRegI(env); +//.. HReg tHi = newVRegI(env); +//.. HReg sHi, sLo; +//.. iselInt64Expr(&sHi, &sLo, env, e->Iex.Unop.arg); +//.. addInstr(env, mk_iMOVsd_RR(sHi, tHi)); +//.. addInstr(env, mk_iMOVsd_RR(sLo, tLo)); +//.. addInstr(env, X86Instr_Unary32(Xun_NOT,X86RM_Reg(tHi))); +//.. addInstr(env, X86Instr_Unary32(Xun_NOT,X86RM_Reg(tLo))); +//.. *rHi = tHi; +//.. *rLo = tLo; +//.. return; +//.. } +//.. +//.. /* ReinterpF64asI64(e) */ +//.. /* Given an IEEE754 double, produce an I64 with the same bit +//.. pattern. */ +//.. case Iop_ReinterpF64asI64: { +//.. HReg rf = iselDblExpr(env, e->Iex.Unop.arg); +//.. HReg tLo = newVRegI(env); +//.. HReg tHi = newVRegI(env); +//.. X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP()); +//.. X86AMode* four_esp = X86AMode_IR(4, hregX86_ESP()); +//.. /* paranoia */ +//.. set_FPU_rounding_default(env); +//.. /* subl $8, %esp */ +//.. sub_from_esp(env, 8); +//.. /* gstD %rf, 0(%esp) */ +//.. addInstr(env, +//.. X86Instr_FpLdSt(False/*store*/, 8, rf, zero_esp)); +//.. /* movl 0(%esp), %tLo */ +//.. addInstr(env, +//.. X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(zero_esp), tLo)); +//.. /* movl 4(%esp), %tHi */ +//.. addInstr(env, +//.. X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(four_esp), tHi)); +//.. /* addl $8, %esp */ +//.. add_to_esp(env, 8); +//.. *rHi = tHi; +//.. *rLo = tLo; +//.. return; +//.. } +//.. +//.. case Iop_CmpNEZ32x2: +//.. fn = (HWord)h_generic_calc_CmpNEZ32x2; goto unish; +//.. case Iop_CmpNEZ16x4: +//.. fn = (HWord)h_generic_calc_CmpNEZ16x4; goto unish; +//.. case Iop_CmpNEZ8x8: +//.. fn = (HWord)h_generic_calc_CmpNEZ8x8; goto unish; +//.. unish: { +//.. /* Note: the following assumes all helpers are of +//.. signature +//.. ULong fn ( ULong ), and they are +//.. not marked as regparm functions. +//.. */ +//.. HReg xLo, xHi; +//.. HReg tLo = newVRegI(env); +//.. HReg tHi = newVRegI(env); +//.. iselInt64Expr(&xHi, &xLo, env, e->Iex.Unop.arg); +//.. addInstr(env, X86Instr_Push(X86RMI_Reg(xHi))); +//.. addInstr(env, X86Instr_Push(X86RMI_Reg(xLo))); +//.. addInstr(env, X86Instr_Call( Xcc_ALWAYS, (UInt)fn, 0 )); +//.. add_to_esp(env, 2*4); +//.. addInstr(env, mk_iMOVsd_RR(hregX86_EDX(), tHi)); +//.. addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), tLo)); +//.. *rHi = tHi; +//.. *rLo = tLo; +//.. return; +//.. } +//.. +//.. default: +//.. break; +//.. } +//.. } /* if (e->tag == Iex_Unop) */ +//.. +//.. +//.. /* --------- CCALL --------- */ +//.. if (e->tag == Iex_CCall) { +//.. HReg tLo = newVRegI(env); +//.. HReg tHi = newVRegI(env); +//.. +//.. /* Marshal args, do the call, clear stack. */ +//.. doHelperCall( env, False, NULL, e->Iex.CCall.cee, e->Iex.CCall.args ); +//.. +//.. addInstr(env, mk_iMOVsd_RR(hregX86_EDX(), tHi)); +//.. addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), tLo)); +//.. *rHi = tHi; +//.. *rLo = tLo; +//.. return; +//.. } +//.. +//.. ppIRExpr(e); +//.. vpanic("iselInt64Expr"); +//.. } +//.. +//.. +//.. /*---------------------------------------------------------*/ +//.. /*--- ISEL: Floating point expressions (32 bit) ---*/ +//.. /*---------------------------------------------------------*/ +//.. +//.. /* Nothing interesting here; really just wrappers for +//.. 64-bit stuff. */ +//.. +//.. static HReg iselFltExpr ( ISelEnv* env, IRExpr* e ) +//.. { +//.. HReg r = iselFltExpr_wrk( env, e ); +//.. # if 0 +//.. vex_printf("\n"); ppIRExpr(e); vex_printf("\n"); +//.. # endif +//.. vassert(hregClass(r) == HRcFlt64); /* yes, really Flt64 */ +//.. vassert(hregIsVirtual(r)); +//.. return r; +//.. } +//.. +//.. /* DO NOT CALL THIS DIRECTLY */ +//.. static HReg iselFltExpr_wrk ( ISelEnv* env, IRExpr* e ) +//.. { +//.. IRType ty = typeOfIRExpr(env->type_env,e); +//.. vassert(ty == Ity_F32); +//.. +//.. if (e->tag == Iex_Tmp) { +//.. return lookupIRTemp(env, e->Iex.Tmp.tmp); +//.. } +//.. +//.. if (e->tag == Iex_LDle) { +//.. X86AMode* am; +//.. HReg res = newVRegF(env); +//.. vassert(e->Iex.LDle.ty == Ity_F32); +//.. am = iselIntExpr_AMode(env, e->Iex.LDle.addr); +//.. addInstr(env, X86Instr_FpLdSt(True/*load*/, 4, res, am)); +//.. return res; +//.. } +//.. +//.. if (e->tag == Iex_Binop +//.. && e->Iex.Binop.op == Iop_F64toF32) { +//.. /* Although the result is still held in a standard FPU register, +//.. we need to round it to reflect the loss of accuracy/range +//.. entailed in casting it to a 32-bit float. */ +//.. HReg dst = newVRegF(env); +//.. HReg src = iselDblExpr(env, e->Iex.Binop.arg2); +//.. set_FPU_rounding_mode( env, e->Iex.Binop.arg1 ); +//.. addInstr(env, X86Instr_Fp64to32(src,dst)); +//.. set_FPU_rounding_default( env ); +//.. return dst; +//.. } +//.. +//.. if (e->tag == Iex_Get) { +//.. X86AMode* am = X86AMode_IR( e->Iex.Get.offset, +//.. hregX86_EBP() ); +//.. HReg res = newVRegF(env); +//.. addInstr(env, X86Instr_FpLdSt( True/*load*/, 4, res, am )); +//.. return res; +//.. } +//.. +//.. if (e->tag == Iex_Unop +//.. && e->Iex.Unop.op == Iop_ReinterpI32asF32) { +//.. /* Given an I32, produce an IEEE754 float with the same bit +//.. pattern. */ +//.. HReg dst = newVRegF(env); +//.. X86RMI* rmi = iselIntExpr_RMI(env, e->Iex.Unop.arg); +//.. /* paranoia */ +//.. addInstr(env, X86Instr_Push(rmi)); +//.. addInstr(env, X86Instr_FpLdSt( +//.. True/*load*/, 4, dst, +//.. X86AMode_IR(0, hregX86_ESP()))); +//.. add_to_esp(env, 4); +//.. return dst; +//.. } +//.. +//.. ppIRExpr(e); +//.. vpanic("iselFltExpr_wrk"); +//.. } +//.. +//.. +//.. /*---------------------------------------------------------*/ +//.. /*--- ISEL: Floating point expressions (64 bit) ---*/ +//.. /*---------------------------------------------------------*/ +//.. +//.. /* Compute a 64-bit floating point value into a register, the identity +//.. of which is returned. As with iselIntExpr_R, the reg may be either +//.. real or virtual; in any case it must not be changed by subsequent +//.. code emitted by the caller. */ +//.. +//.. /* IEEE 754 formats. From http://www.freesoft.org/CIE/RFC/1832/32.htm: +//.. +//.. Type S (1 bit) E (11 bits) F (52 bits) +//.. ---- --------- ----------- ----------- +//.. signalling NaN u 2047 (max) .0uuuuu---u +//.. (with at least +//.. one 1 bit) +//.. quiet NaN u 2047 (max) .1uuuuu---u +//.. +//.. negative infinity 1 2047 (max) .000000---0 +//.. +//.. positive infinity 0 2047 (max) .000000---0 +//.. +//.. negative zero 1 0 .000000---0 +//.. +//.. positive zero 0 0 .000000---0 +//.. */ +//.. +//.. static HReg iselDblExpr ( ISelEnv* env, IRExpr* e ) +//.. { +//.. HReg r = iselDblExpr_wrk( env, e ); +//.. # if 0 +//.. vex_printf("\n"); ppIRExpr(e); vex_printf("\n"); +//.. # endif +//.. vassert(hregClass(r) == HRcFlt64); +//.. vassert(hregIsVirtual(r)); +//.. return r; +//.. } +//.. +//.. /* DO NOT CALL THIS DIRECTLY */ +//.. static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e ) +//.. { +//.. IRType ty = typeOfIRExpr(env->type_env,e); +//.. vassert(e); +//.. vassert(ty == Ity_F64); +//.. +//.. if (e->tag == Iex_Tmp) { +//.. return lookupIRTemp(env, e->Iex.Tmp.tmp); +//.. } +//.. +//.. if (e->tag == Iex_Const) { +//.. union { UInt u32x2[2]; ULong u64; Double f64; } u; +//.. HReg freg = newVRegF(env); +//.. vassert(sizeof(u) == 8); +//.. vassert(sizeof(u.u64) == 8); +//.. vassert(sizeof(u.f64) == 8); +//.. vassert(sizeof(u.u32x2) == 8); +//.. +//.. if (e->Iex.Const.con->tag == Ico_F64) { +//.. u.f64 = e->Iex.Const.con->Ico.F64; +//.. } +//.. else if (e->Iex.Const.con->tag == Ico_F64i) { +//.. u.u64 = e->Iex.Const.con->Ico.F64i; +//.. } +//.. else +//.. vpanic("iselDblExpr(x86): const"); +//.. +//.. addInstr(env, X86Instr_Push(X86RMI_Imm(u.u32x2[1]))); +//.. addInstr(env, X86Instr_Push(X86RMI_Imm(u.u32x2[0]))); +//.. addInstr(env, X86Instr_FpLdSt(True/*load*/, 8, freg, +//.. X86AMode_IR(0, hregX86_ESP()))); +//.. add_to_esp(env, 8); +//.. return freg; +//.. } +//.. +//.. if (e->tag == Iex_LDle) { +//.. X86AMode* am; +//.. HReg res = newVRegF(env); +//.. vassert(e->Iex.LDle.ty == Ity_F64); +//.. am = iselIntExpr_AMode(env, e->Iex.LDle.addr); +//.. addInstr(env, X86Instr_FpLdSt(True/*load*/, 8, res, am)); +//.. return res; +//.. } +//.. +//.. if (e->tag == Iex_Get) { +//.. X86AMode* am = X86AMode_IR( e->Iex.Get.offset, +//.. hregX86_EBP() ); +//.. HReg res = newVRegF(env); +//.. addInstr(env, X86Instr_FpLdSt( True/*load*/, 8, res, am )); +//.. return res; +//.. } +//.. +//.. if (e->tag == Iex_GetI) { +//.. X86AMode* am +//.. = genGuestArrayOffset( +//.. env, e->Iex.GetI.descr, +//.. e->Iex.GetI.ix, e->Iex.GetI.bias ); +//.. HReg res = newVRegF(env); +//.. addInstr(env, X86Instr_FpLdSt( True/*load*/, 8, res, am )); +//.. return res; +//.. } +//.. +//.. if (e->tag == Iex_Binop) { +//.. X86FpOp fpop = Xfp_INVALID; +//.. switch (e->Iex.Binop.op) { +//.. case Iop_AddF64: fpop = Xfp_ADD; break; +//.. case Iop_SubF64: fpop = Xfp_SUB; break; +//.. case Iop_MulF64: fpop = Xfp_MUL; break; +//.. case Iop_DivF64: fpop = Xfp_DIV; break; +//.. case Iop_ScaleF64: fpop = Xfp_SCALE; break; +//.. case Iop_AtanF64: fpop = Xfp_ATAN; break; +//.. case Iop_Yl2xF64: fpop = Xfp_YL2X; break; +//.. case Iop_Yl2xp1F64: fpop = Xfp_YL2XP1; break; +//.. case Iop_PRemF64: fpop = Xfp_PREM; break; +//.. case Iop_PRem1F64: fpop = Xfp_PREM1; break; +//.. default: break; +//.. } +//.. if (fpop != Xfp_INVALID) { +//.. HReg res = newVRegF(env); +//.. HReg srcL = iselDblExpr(env, e->Iex.Binop.arg1); +//.. HReg srcR = iselDblExpr(env, e->Iex.Binop.arg2); +//.. addInstr(env, X86Instr_FpBinary(fpop,srcL,srcR,res)); +//.. if (fpop != Xfp_ADD && fpop != Xfp_SUB +//.. && fpop != Xfp_MUL && fpop != Xfp_DIV) +//.. roundToF64(env, res); +//.. return res; +//.. } +//.. } +//.. +//.. if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_RoundF64) { +//.. HReg rf = iselDblExpr(env, e->Iex.Binop.arg2); +//.. HReg dst = newVRegF(env); +//.. +//.. /* rf now holds the value to be rounded. The first thing to do +//.. is set the FPU's rounding mode accordingly. */ +//.. +//.. /* Set host rounding mode */ +//.. set_FPU_rounding_mode( env, e->Iex.Binop.arg1 ); +//.. +//.. /* grndint %rf, %dst */ +//.. addInstr(env, X86Instr_FpUnary(Xfp_ROUND, rf, dst)); +//.. +//.. /* Restore default FPU rounding. */ +//.. set_FPU_rounding_default( env ); +//.. +//.. return dst; +//.. } +//.. +//.. if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_I64toF64) { +//.. HReg dst = newVRegF(env); +//.. HReg rHi,rLo; +//.. iselInt64Expr( &rHi, &rLo, env, e->Iex.Binop.arg2); +//.. addInstr(env, X86Instr_Push(X86RMI_Reg(rHi))); +//.. addInstr(env, X86Instr_Push(X86RMI_Reg(rLo))); +//.. +//.. /* Set host rounding mode */ +//.. set_FPU_rounding_mode( env, e->Iex.Binop.arg1 ); +//.. +//.. addInstr(env, X86Instr_FpLdStI( +//.. True/*load*/, 8, dst, +//.. X86AMode_IR(0, hregX86_ESP()))); +//.. +//.. /* Restore default FPU rounding. */ +//.. set_FPU_rounding_default( env ); +//.. +//.. add_to_esp(env, 8); +//.. return dst; +//.. } +//.. +//.. if (e->tag == Iex_Unop) { +//.. X86FpOp fpop = Xfp_INVALID; +//.. switch (e->Iex.Unop.op) { +//.. case Iop_NegF64: fpop = Xfp_NEG; break; +//.. case Iop_AbsF64: fpop = Xfp_ABS; break; +//.. case Iop_SqrtF64: fpop = Xfp_SQRT; break; +//.. case Iop_SinF64: fpop = Xfp_SIN; break; +//.. case Iop_CosF64: fpop = Xfp_COS; break; +//.. case Iop_TanF64: fpop = Xfp_TAN; break; +//.. case Iop_2xm1F64: fpop = Xfp_2XM1; break; +//.. default: break; +//.. } +//.. if (fpop != Xfp_INVALID) { +//.. HReg res = newVRegF(env); +//.. HReg src = iselDblExpr(env, e->Iex.Unop.arg); +//.. addInstr(env, X86Instr_FpUnary(fpop,src,res)); +//.. if (fpop != Xfp_SQRT +//.. && fpop != Xfp_NEG && fpop != Xfp_ABS) +//.. roundToF64(env, res); +//.. return res; +//.. } +//.. } +//.. +//.. if (e->tag == Iex_Unop) { +//.. switch (e->Iex.Unop.op) { +//.. case Iop_I32toF64: { +//.. HReg dst = newVRegF(env); +//.. HReg ri = iselIntExpr_R(env, e->Iex.Unop.arg); +//.. addInstr(env, X86Instr_Push(X86RMI_Reg(ri))); +//.. set_FPU_rounding_default(env); +//.. addInstr(env, X86Instr_FpLdStI( +//.. True/*load*/, 4, dst, +//.. X86AMode_IR(0, hregX86_ESP()))); +//.. add_to_esp(env, 4); +//.. return dst; +//.. } +//.. case Iop_ReinterpI64asF64: { +//.. /* Given an I64, produce an IEEE754 double with the same +//.. bit pattern. */ +//.. HReg dst = newVRegF(env); +//.. HReg rHi, rLo; +//.. iselInt64Expr( &rHi, &rLo, env, e->Iex.Unop.arg); +//.. /* paranoia */ +//.. set_FPU_rounding_default(env); +//.. addInstr(env, X86Instr_Push(X86RMI_Reg(rHi))); +//.. addInstr(env, X86Instr_Push(X86RMI_Reg(rLo))); +//.. addInstr(env, X86Instr_FpLdSt( +//.. True/*load*/, 8, dst, +//.. X86AMode_IR(0, hregX86_ESP()))); +//.. add_to_esp(env, 8); +//.. return dst; +//.. } +//.. case Iop_F32toF64: { +//.. /* this is a no-op */ +//.. HReg res = iselFltExpr(env, e->Iex.Unop.arg); +//.. return res; +//.. } +//.. default: +//.. break; +//.. } +//.. } +//.. +//.. /* --------- MULTIPLEX --------- */ +//.. if (e->tag == Iex_Mux0X) { +//.. if (ty == Ity_F64 +//.. && typeOfIRExpr(env->type_env,e->Iex.Mux0X.cond) == Ity_I8) { +//.. HReg r8 = iselIntExpr_R(env, e->Iex.Mux0X.cond); +//.. HReg rX = iselDblExpr(env, e->Iex.Mux0X.exprX); +//.. HReg r0 = iselDblExpr(env, e->Iex.Mux0X.expr0); +//.. HReg dst = newVRegF(env); +//.. addInstr(env, X86Instr_FpUnary(Xfp_MOV,rX,dst)); +//.. addInstr(env, X86Instr_Test32(X86RI_Imm(0xFF), X86RM_Reg(r8))); +//.. addInstr(env, X86Instr_FpCMov(Xcc_Z,r0,dst)); +//.. return dst; +//.. } +//.. } +//.. +//.. ppIRExpr(e); +//.. vpanic("iselDblExpr_wrk"); +//.. } +//.. +//.. +//.. /*---------------------------------------------------------*/ +//.. /*--- ISEL: SIMD (Vector) expressions, 128 bit. ---*/ +//.. /*---------------------------------------------------------*/ +//.. +//.. static HReg iselVecExpr ( ISelEnv* env, IRExpr* e ) +//.. { +//.. HReg r = iselVecExpr_wrk( env, e ); +//.. # if 0 +//.. vex_printf("\n"); ppIRExpr(e); vex_printf("\n"); +//.. # endif +//.. vassert(hregClass(r) == HRcVec128); +//.. vassert(hregIsVirtual(r)); +//.. return r; +//.. } +//.. +//.. +//.. /* DO NOT CALL THIS DIRECTLY */ +//.. static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e ) +//.. { +//.. +/* +//.. # define REQUIRE_SSE1 \ +//.. do { if (env->subarch == VexSubArchX86_sse0) \ +//.. goto vec_fail; \ +//.. } while (0) +//.. +//.. # define REQUIRE_SSE2 \ +//.. do { if (env->subarch == VexSubArchX86_sse0 \ +//.. || env->subarch == VexSubArchX86_sse1) \ +//.. goto vec_fail; \ +//.. } while (0) +*/ +//.. Bool arg1isEReg = False; +//.. X86SseOp op = Xsse_INVALID; +//.. IRType ty = typeOfIRExpr(env->type_env,e); +//.. vassert(e); +//.. vassert(ty == Ity_V128); +//.. +//.. REQUIRE_SSE1; +//.. +//.. if (e->tag == Iex_Tmp) { +//.. return lookupIRTemp(env, e->Iex.Tmp.tmp); +//.. } +//.. +//.. if (e->tag == Iex_Get) { +//.. HReg dst = newVRegV(env); +//.. addInstr(env, X86Instr_SseLdSt( +//.. True/*load*/, +//.. dst, +//.. X86AMode_IR(e->Iex.Get.offset, hregX86_EBP()) +//.. ) +//.. ); +//.. return dst; +//.. } +//.. +//.. if (e->tag == Iex_LDle) { +//.. HReg dst = newVRegV(env); +//.. X86AMode* am = iselIntExpr_AMode(env, e->Iex.LDle.addr); +//.. addInstr(env, X86Instr_SseLdSt( True/*load*/, dst, am )); +//.. return dst; +//.. } +//.. +//.. if (e->tag == Iex_Const) { +//.. HReg dst = newVRegV(env); +//.. vassert(e->Iex.Const.con->tag == Ico_V128); +//.. addInstr(env, X86Instr_SseConst(e->Iex.Const.con->Ico.V128, dst)); +//.. return dst; +//.. } +//.. +//.. if (e->tag == Iex_Unop) { +//.. switch (e->Iex.Unop.op) { +//.. +//.. case Iop_Not128: { +//.. HReg arg = iselVecExpr(env, e->Iex.Unop.arg); +//.. return do_sse_Not128(env, arg); +//.. } +//.. +//.. case Iop_CmpNEZ64x2: { +//.. /* We can use SSE2 instructions for this. */ +//.. /* Ideally, we want to do a 64Ix2 comparison against zero of +//.. the operand. Problem is no such insn exists. Solution +//.. therefore is to do a 32Ix4 comparison instead, and bitwise- +//.. negate (NOT) the result. Let a,b,c,d be 32-bit lanes, and +//.. let the not'd result of this initial comparison be a:b:c:d. +//.. What we need to compute is (a|b):(a|b):(c|d):(c|d). So, use +//.. pshufd to create a value b:a:d:c, and OR that with a:b:c:d, +//.. giving the required result. +//.. +//.. The required selection sequence is 2,3,0,1, which +//.. according to Intel's documentation means the pshufd +//.. literal value is 0xB1, that is, +//.. (2 << 6) | (3 << 4) | (0 << 2) | (1 << 0) +//.. */ +//.. HReg arg = iselVecExpr(env, e->Iex.Unop.arg); +//.. HReg tmp = newVRegV(env); +//.. HReg dst = newVRegV(env); +//.. REQUIRE_SSE2; +//.. addInstr(env, X86Instr_SseReRg(Xsse_XOR, tmp, tmp)); +//.. addInstr(env, X86Instr_SseReRg(Xsse_CMPEQ32, arg, tmp)); +//.. tmp = do_sse_Not128(env, tmp); +//.. addInstr(env, X86Instr_SseShuf(0xB1, tmp, dst)); +//.. addInstr(env, X86Instr_SseReRg(Xsse_OR, tmp, dst)); +//.. return dst; +//.. } +//.. +//.. case Iop_CmpNEZ32x4: { +//.. /* Sigh, we have to generate lousy code since this has to +//.. work on SSE1 hosts */ +//.. /* basically, the idea is: for each lane: +//.. movl lane, %r ; negl %r (now CF = lane==0 ? 0 : 1) +//.. sbbl %r, %r (now %r = 1Sto32(CF)) +//.. movl %r, lane +//.. */ +//.. Int i; +//.. X86AMode* am; +//.. X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP()); +//.. HReg arg = iselVecExpr(env, e->Iex.Unop.arg); +//.. HReg dst = newVRegV(env); +//.. HReg r32 = newVRegI(env); +//.. sub_from_esp(env, 16); +//.. addInstr(env, X86Instr_SseLdSt(False/*store*/, arg, esp0)); +//.. for (i = 0; i < 4; i++) { +//.. am = X86AMode_IR(i*4, hregX86_ESP()); +//.. addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(am), r32)); +//.. addInstr(env, X86Instr_Unary32(Xun_NEG, X86RM_Reg(r32))); +//.. addInstr(env, X86Instr_Alu32R(Xalu_SBB, X86RMI_Reg(r32), r32)); +//.. addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(r32), am)); +//.. } +//.. addInstr(env, X86Instr_SseLdSt(True/*load*/, dst, esp0)); +//.. add_to_esp(env, 16); +//.. return dst; +//.. } +//.. +//.. case Iop_CmpNEZ8x16: +//.. case Iop_CmpNEZ16x8: { +//.. /* We can use SSE2 instructions for this. */ +//.. HReg arg; +//.. HReg vec0 = newVRegV(env); +//.. HReg vec1 = newVRegV(env); +//.. HReg dst = newVRegV(env); +//.. X86SseOp cmpOp +//.. = e->Iex.Unop.op==Iop_CmpNEZ16x8 ? Xsse_CMPEQ16 +//.. : Xsse_CMPEQ8; +//.. REQUIRE_SSE2; +//.. addInstr(env, X86Instr_SseReRg(Xsse_XOR, vec0, vec0)); +//.. addInstr(env, mk_vMOVsd_RR(vec0, vec1)); +//.. addInstr(env, X86Instr_Sse32Fx4(Xsse_CMPEQF, vec1, vec1)); +//.. /* defer arg computation to here so as to give CMPEQF as long +//.. as possible to complete */ +//.. arg = iselVecExpr(env, e->Iex.Unop.arg); +//.. /* vec0 is all 0s; vec1 is all 1s */ +//.. addInstr(env, mk_vMOVsd_RR(arg, dst)); +//.. /* 16x8 or 8x16 comparison == */ +//.. addInstr(env, X86Instr_SseReRg(cmpOp, vec0, dst)); +//.. /* invert result */ +//.. addInstr(env, X86Instr_SseReRg(Xsse_XOR, vec1, dst)); +//.. return dst; +//.. } +//.. +//.. case Iop_Recip32Fx4: op = Xsse_RCPF; goto do_32Fx4_unary; +//.. case Iop_RSqrt32Fx4: op = Xsse_RSQRTF; goto do_32Fx4_unary; +//.. case Iop_Sqrt32Fx4: op = Xsse_SQRTF; goto do_32Fx4_unary; +//.. do_32Fx4_unary: +//.. { +//.. HReg arg = iselVecExpr(env, e->Iex.Unop.arg); +//.. HReg dst = newVRegV(env); +//.. addInstr(env, X86Instr_Sse32Fx4(op, arg, dst)); +//.. return dst; +//.. } +//.. +//.. case Iop_Recip64Fx2: op = Xsse_RCPF; goto do_64Fx2_unary; +//.. case Iop_RSqrt64Fx2: op = Xsse_RSQRTF; goto do_64Fx2_unary; +//.. case Iop_Sqrt64Fx2: op = Xsse_SQRTF; goto do_64Fx2_unary; +//.. do_64Fx2_unary: +//.. { +//.. HReg arg = iselVecExpr(env, e->Iex.Unop.arg); +//.. HReg dst = newVRegV(env); +//.. REQUIRE_SSE2; +//.. addInstr(env, X86Instr_Sse64Fx2(op, arg, dst)); +//.. return dst; +//.. } +//.. +//.. case Iop_Recip32F0x4: op = Xsse_RCPF; goto do_32F0x4_unary; +//.. case Iop_RSqrt32F0x4: op = Xsse_RSQRTF; goto do_32F0x4_unary; +//.. case Iop_Sqrt32F0x4: op = Xsse_SQRTF; goto do_32F0x4_unary; +//.. do_32F0x4_unary: +//.. { +//.. /* A bit subtle. We have to copy the arg to the result +//.. register first, because actually doing the SSE scalar insn +//.. leaves the upper 3/4 of the destination register +//.. unchanged. Whereas the required semantics of these +//.. primops is that the upper 3/4 is simply copied in from the +//.. argument. */ +//.. HReg arg = iselVecExpr(env, e->Iex.Unop.arg); +//.. HReg dst = newVRegV(env); +//.. addInstr(env, mk_vMOVsd_RR(arg, dst)); +//.. addInstr(env, X86Instr_Sse32FLo(op, arg, dst)); +//.. return dst; +//.. } +//.. +//.. case Iop_Recip64F0x2: op = Xsse_RCPF; goto do_64F0x2_unary; +//.. case Iop_RSqrt64F0x2: op = Xsse_RSQRTF; goto do_64F0x2_unary; +//.. case Iop_Sqrt64F0x2: op = Xsse_SQRTF; goto do_64F0x2_unary; +//.. do_64F0x2_unary: +//.. { +//.. /* A bit subtle. We have to copy the arg to the result +//.. register first, because actually doing the SSE scalar insn +//.. leaves the upper half of the destination register +//.. unchanged. Whereas the required semantics of these +//.. primops is that the upper half is simply copied in from the +//.. argument. */ +//.. HReg arg = iselVecExpr(env, e->Iex.Unop.arg); +//.. HReg dst = newVRegV(env); +//.. REQUIRE_SSE2; +//.. addInstr(env, mk_vMOVsd_RR(arg, dst)); +//.. addInstr(env, X86Instr_Sse64FLo(op, arg, dst)); +//.. return dst; +//.. } +//.. +//.. case Iop_32Uto128: { +//.. HReg dst = newVRegV(env); +//.. X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP()); +//.. X86RMI* rmi = iselIntExpr_RMI(env, e->Iex.Unop.arg); +//.. addInstr(env, X86Instr_Push(rmi)); +//.. addInstr(env, X86Instr_SseLdzLO(4, dst, esp0)); +//.. add_to_esp(env, 4); +//.. return dst; +//.. } +//.. +//.. case Iop_64Uto128: { +//.. HReg rHi, rLo; +//.. HReg dst = newVRegV(env); +//.. X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP()); +//.. iselInt64Expr(&rHi, &rLo, env, e->Iex.Unop.arg); +//.. addInstr(env, X86Instr_Push(X86RMI_Reg(rHi))); +//.. addInstr(env, X86Instr_Push(X86RMI_Reg(rLo))); +//.. addInstr(env, X86Instr_SseLdzLO(8, dst, esp0)); +//.. add_to_esp(env, 8); +//.. return dst; +//.. } +//.. +//.. default: +//.. break; +//.. } /* switch (e->Iex.Unop.op) */ +//.. } /* if (e->tag == Iex_Unop) */ +//.. +//.. if (e->tag == Iex_Binop) { +//.. switch (e->Iex.Binop.op) { +//.. +//.. case Iop_Set128lo32: { +//.. HReg dst = newVRegV(env); +//.. HReg srcV = iselVecExpr(env, e->Iex.Binop.arg1); +//.. HReg srcI = iselIntExpr_R(env, e->Iex.Binop.arg2); +//.. X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP()); +//.. sub_from_esp(env, 16); +//.. addInstr(env, X86Instr_SseLdSt(False/*store*/, srcV, esp0)); +//.. addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(srcI), esp0)); +//.. addInstr(env, X86Instr_SseLdSt(True/*load*/, dst, esp0)); +//.. add_to_esp(env, 16); +//.. return dst; +//.. } +//.. +//.. case Iop_Set128lo64: { +//.. HReg dst = newVRegV(env); +//.. HReg srcV = iselVecExpr(env, e->Iex.Binop.arg1); +//.. HReg srcIhi, srcIlo; +//.. X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP()); +//.. X86AMode* esp4 = advance4(esp0); +//.. iselInt64Expr(&srcIhi, &srcIlo, env, e->Iex.Binop.arg2); +//.. sub_from_esp(env, 16); +//.. addInstr(env, X86Instr_SseLdSt(False/*store*/, srcV, esp0)); +//.. addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(srcIlo), esp0)); +//.. addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(srcIhi), esp4)); +//.. addInstr(env, X86Instr_SseLdSt(True/*load*/, dst, esp0)); +//.. add_to_esp(env, 16); +//.. return dst; +//.. } +//.. +//.. case Iop_64HLto128: { +//.. HReg r3, r2, r1, r0; +//.. X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP()); +//.. X86AMode* esp4 = advance4(esp0); +//.. X86AMode* esp8 = advance4(esp4); +//.. X86AMode* esp12 = advance4(esp8); +//.. HReg dst = newVRegV(env); +//.. /* do this via the stack (easy, convenient, etc) */ +//.. sub_from_esp(env, 16); +//.. /* Do the less significant 64 bits */ +//.. iselInt64Expr(&r1, &r0, env, e->Iex.Binop.arg2); +//.. addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(r0), esp0)); +//.. addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(r1), esp4)); +//.. /* Do the more significant 64 bits */ +//.. iselInt64Expr(&r3, &r2, env, e->Iex.Binop.arg1); +//.. addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(r2), esp8)); +//.. addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(r3), esp12)); +//.. /* Fetch result back from stack. */ +//.. addInstr(env, X86Instr_SseLdSt(True/*load*/, dst, esp0)); +//.. add_to_esp(env, 16); +//.. return dst; +//.. } +//.. +//.. case Iop_CmpEQ32Fx4: op = Xsse_CMPEQF; goto do_32Fx4; +//.. case Iop_CmpLT32Fx4: op = Xsse_CMPLTF; goto do_32Fx4; +//.. case Iop_CmpLE32Fx4: op = Xsse_CMPLEF; goto do_32Fx4; +//.. case Iop_Add32Fx4: op = Xsse_ADDF; goto do_32Fx4; +//.. case Iop_Div32Fx4: op = Xsse_DIVF; goto do_32Fx4; +//.. case Iop_Max32Fx4: op = Xsse_MAXF; goto do_32Fx4; +//.. case Iop_Min32Fx4: op = Xsse_MINF; goto do_32Fx4; +//.. case Iop_Mul32Fx4: op = Xsse_MULF; goto do_32Fx4; +//.. case Iop_Sub32Fx4: op = Xsse_SUBF; goto do_32Fx4; +//.. do_32Fx4: +//.. { +//.. HReg argL = iselVecExpr(env, e->Iex.Binop.arg1); +//.. HReg argR = iselVecExpr(env, e->Iex.Binop.arg2); +//.. HReg dst = newVRegV(env); +//.. addInstr(env, mk_vMOVsd_RR(argL, dst)); +//.. addInstr(env, X86Instr_Sse32Fx4(op, argR, dst)); +//.. return dst; +//.. } +//.. +//.. case Iop_CmpEQ64Fx2: op = Xsse_CMPEQF; goto do_64Fx2; +//.. case Iop_CmpLT64Fx2: op = Xsse_CMPLTF; goto do_64Fx2; +//.. case Iop_CmpLE64Fx2: op = Xsse_CMPLEF; goto do_64Fx2; +//.. case Iop_Add64Fx2: op = Xsse_ADDF; goto do_64Fx2; +//.. case Iop_Div64Fx2: op = Xsse_DIVF; goto do_64Fx2; +//.. case Iop_Max64Fx2: op = Xsse_MAXF; goto do_64Fx2; +//.. case Iop_Min64Fx2: op = Xsse_MINF; goto do_64Fx2; +//.. case Iop_Mul64Fx2: op = Xsse_MULF; goto do_64Fx2; +//.. case Iop_Sub64Fx2: op = Xsse_SUBF; goto do_64Fx2; +//.. do_64Fx2: +//.. { +//.. HReg argL = iselVecExpr(env, e->Iex.Binop.arg1); +//.. HReg argR = iselVecExpr(env, e->Iex.Binop.arg2); +//.. HReg dst = newVRegV(env); +//.. REQUIRE_SSE2; +//.. addInstr(env, mk_vMOVsd_RR(argL, dst)); +//.. addInstr(env, X86Instr_Sse64Fx2(op, argR, dst)); +//.. return dst; +//.. } +//.. +//.. case Iop_CmpEQ32F0x4: op = Xsse_CMPEQF; goto do_32F0x4; +//.. case Iop_CmpLT32F0x4: op = Xsse_CMPLTF; goto do_32F0x4; +//.. case Iop_CmpLE32F0x4: op = Xsse_CMPLEF; goto do_32F0x4; +//.. case Iop_Add32F0x4: op = Xsse_ADDF; goto do_32F0x4; +//.. case Iop_Div32F0x4: op = Xsse_DIVF; goto do_32F0x4; +//.. case Iop_Max32F0x4: op = Xsse_MAXF; goto do_32F0x4; +//.. case Iop_Min32F0x4: op = Xsse_MINF; goto do_32F0x4; +//.. case Iop_Mul32F0x4: op = Xsse_MULF; goto do_32F0x4; +//.. case Iop_Sub32F0x4: op = Xsse_SUBF; goto do_32F0x4; +//.. do_32F0x4: { +//.. HReg argL = iselVecExpr(env, e->Iex.Binop.arg1); +//.. HReg argR = iselVecExpr(env, e->Iex.Binop.arg2); +//.. HReg dst = newVRegV(env); +//.. addInstr(env, mk_vMOVsd_RR(argL, dst)); +//.. addInstr(env, X86Instr_Sse32FLo(op, argR, dst)); +//.. return dst; +//.. } +//.. +//.. case Iop_CmpEQ64F0x2: op = Xsse_CMPEQF; goto do_64F0x2; +//.. case Iop_CmpLT64F0x2: op = Xsse_CMPLTF; goto do_64F0x2; +//.. case Iop_CmpLE64F0x2: op = Xsse_CMPLEF; goto do_64F0x2; +//.. case Iop_Add64F0x2: op = Xsse_ADDF; goto do_64F0x2; +//.. case Iop_Div64F0x2: op = Xsse_DIVF; goto do_64F0x2; +//.. case Iop_Max64F0x2: op = Xsse_MAXF; goto do_64F0x2; +//.. case Iop_Min64F0x2: op = Xsse_MINF; goto do_64F0x2; +//.. case Iop_Mul64F0x2: op = Xsse_MULF; goto do_64F0x2; +//.. case Iop_Sub64F0x2: op = Xsse_SUBF; goto do_64F0x2; +//.. do_64F0x2: { +//.. HReg argL = iselVecExpr(env, e->Iex.Binop.arg1); +//.. HReg argR = iselVecExpr(env, e->Iex.Binop.arg2); +//.. HReg dst = newVRegV(env); +//.. REQUIRE_SSE2; +//.. addInstr(env, mk_vMOVsd_RR(argL, dst)); +//.. addInstr(env, X86Instr_Sse64FLo(op, argR, dst)); +//.. return dst; +//.. } +//.. +//.. case Iop_QNarrow32Sx4: +//.. op = Xsse_PACKSSD; arg1isEReg = True; goto do_SseReRg; +//.. case Iop_QNarrow16Sx8: +//.. op = Xsse_PACKSSW; arg1isEReg = True; goto do_SseReRg; +//.. case Iop_QNarrow16Ux8: +//.. op = Xsse_PACKUSW; arg1isEReg = True; goto do_SseReRg; +//.. +//.. case Iop_InterleaveHI8x16: +//.. op = Xsse_UNPCKHB; arg1isEReg = True; goto do_SseReRg; +//.. case Iop_InterleaveHI16x8: +//.. op = Xsse_UNPCKHW; arg1isEReg = True; goto do_SseReRg; +//.. case Iop_InterleaveHI32x4: +//.. op = Xsse_UNPCKHD; arg1isEReg = True; goto do_SseReRg; +//.. case Iop_InterleaveHI64x2: +//.. op = Xsse_UNPCKHQ; arg1isEReg = True; goto do_SseReRg; +//.. +//.. case Iop_InterleaveLO8x16: +//.. op = Xsse_UNPCKLB; arg1isEReg = True; goto do_SseReRg; +//.. case Iop_InterleaveLO16x8: +//.. op = Xsse_UNPCKLW; arg1isEReg = True; goto do_SseReRg; +//.. case Iop_InterleaveLO32x4: +//.. op = Xsse_UNPCKLD; arg1isEReg = True; goto do_SseReRg; +//.. case Iop_InterleaveLO64x2: +//.. op = Xsse_UNPCKLQ; arg1isEReg = True; goto do_SseReRg; +//.. +//.. case Iop_And128: op = Xsse_AND; goto do_SseReRg; +//.. case Iop_Or128: op = Xsse_OR; goto do_SseReRg; +//.. case Iop_Xor128: op = Xsse_XOR; goto do_SseReRg; +//.. case Iop_Add8x16: op = Xsse_ADD8; goto do_SseReRg; +//.. case Iop_Add16x8: op = Xsse_ADD16; goto do_SseReRg; +//.. case Iop_Add32x4: op = Xsse_ADD32; goto do_SseReRg; +//.. case Iop_Add64x2: op = Xsse_ADD64; goto do_SseReRg; +//.. case Iop_QAdd8Sx16: op = Xsse_QADD8S; goto do_SseReRg; +//.. case Iop_QAdd16Sx8: op = Xsse_QADD16S; goto do_SseReRg; +//.. case Iop_QAdd8Ux16: op = Xsse_QADD8U; goto do_SseReRg; +//.. case Iop_QAdd16Ux8: op = Xsse_QADD16U; goto do_SseReRg; +//.. case Iop_Avg8Ux16: op = Xsse_AVG8U; goto do_SseReRg; +//.. case Iop_Avg16Ux8: op = Xsse_AVG16U; goto do_SseReRg; +//.. case Iop_CmpEQ8x16: op = Xsse_CMPEQ8; goto do_SseReRg; +//.. case Iop_CmpEQ16x8: op = Xsse_CMPEQ16; goto do_SseReRg; +//.. case Iop_CmpEQ32x4: op = Xsse_CMPEQ32; goto do_SseReRg; +//.. case Iop_CmpGT8Sx16: op = Xsse_CMPGT8S; goto do_SseReRg; +//.. case Iop_CmpGT16Sx8: op = Xsse_CMPGT16S; goto do_SseReRg; +//.. case Iop_CmpGT32Sx4: op = Xsse_CMPGT32S; goto do_SseReRg; +//.. case Iop_Max16Sx8: op = Xsse_MAX16S; goto do_SseReRg; +//.. case Iop_Max8Ux16: op = Xsse_MAX8U; goto do_SseReRg; +//.. case Iop_Min16Sx8: op = Xsse_MIN16S; goto do_SseReRg; +//.. case Iop_Min8Ux16: op = Xsse_MIN8U; goto do_SseReRg; +//.. case Iop_MulHi16Ux8: op = Xsse_MULHI16U; goto do_SseReRg; +//.. case Iop_MulHi16Sx8: op = Xsse_MULHI16S; goto do_SseReRg; +//.. case Iop_Mul16x8: op = Xsse_MUL16; goto do_SseReRg; +//.. case Iop_Sub8x16: op = Xsse_SUB8; goto do_SseReRg; +//.. case Iop_Sub16x8: op = Xsse_SUB16; goto do_SseReRg; +//.. case Iop_Sub32x4: op = Xsse_SUB32; goto do_SseReRg; +//.. case Iop_Sub64x2: op = Xsse_SUB64; goto do_SseReRg; +//.. case Iop_QSub8Sx16: op = Xsse_QSUB8S; goto do_SseReRg; +//.. case Iop_QSub16Sx8: op = Xsse_QSUB16S; goto do_SseReRg; +//.. case Iop_QSub8Ux16: op = Xsse_QSUB8U; goto do_SseReRg; +//.. case Iop_QSub16Ux8: op = Xsse_QSUB16U; goto do_SseReRg; +//.. do_SseReRg: { +//.. HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1); +//.. HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2); +//.. HReg dst = newVRegV(env); +//.. if (op != Xsse_OR && op != Xsse_AND && op != Xsse_XOR) +//.. REQUIRE_SSE2; +//.. if (arg1isEReg) { +//.. addInstr(env, mk_vMOVsd_RR(arg2, dst)); +//.. addInstr(env, X86Instr_SseReRg(op, arg1, dst)); +//.. } else { +//.. addInstr(env, mk_vMOVsd_RR(arg1, dst)); +//.. addInstr(env, X86Instr_SseReRg(op, arg2, dst)); +//.. } +//.. return dst; +//.. } +//.. +//.. case Iop_ShlN16x8: op = Xsse_SHL16; goto do_SseShift; +//.. case Iop_ShlN32x4: op = Xsse_SHL32; goto do_SseShift; +//.. case Iop_ShlN64x2: op = Xsse_SHL64; goto do_SseShift; +//.. case Iop_SarN16x8: op = Xsse_SAR16; goto do_SseShift; +//.. case Iop_SarN32x4: op = Xsse_SAR32; goto do_SseShift; +//.. case Iop_ShrN16x8: op = Xsse_SHR16; goto do_SseShift; +//.. case Iop_ShrN32x4: op = Xsse_SHR32; goto do_SseShift; +//.. case Iop_ShrN64x2: op = Xsse_SHR64; goto do_SseShift; +//.. do_SseShift: { +//.. HReg greg = iselVecExpr(env, e->Iex.Binop.arg1); +//.. X86RMI* rmi = iselIntExpr_RMI(env, e->Iex.Binop.arg2); +//.. X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP()); +//.. HReg ereg = newVRegV(env); +//.. HReg dst = newVRegV(env); +//.. REQUIRE_SSE2; +//.. addInstr(env, X86Instr_Push(X86RMI_Imm(0))); +//.. addInstr(env, X86Instr_Push(X86RMI_Imm(0))); +//.. addInstr(env, X86Instr_Push(X86RMI_Imm(0))); +//.. addInstr(env, X86Instr_Push(rmi)); +//.. addInstr(env, X86Instr_SseLdSt(True/*load*/, ereg, esp0)); +//.. addInstr(env, mk_vMOVsd_RR(greg, dst)); +//.. addInstr(env, X86Instr_SseReRg(op, ereg, dst)); +//.. add_to_esp(env, 16); +//.. return dst; +//.. } +//.. +//.. default: +//.. break; +//.. } /* switch (e->Iex.Binop.op) */ +//.. } /* if (e->tag == Iex_Binop) */ +//.. +//.. if (e->tag == Iex_Mux0X) { +//.. HReg r8 = iselIntExpr_R(env, e->Iex.Mux0X.cond); +//.. HReg rX = iselVecExpr(env, e->Iex.Mux0X.exprX); +//.. HReg r0 = iselVecExpr(env, e->Iex.Mux0X.expr0); +//.. HReg dst = newVRegV(env); +//.. addInstr(env, mk_vMOVsd_RR(rX,dst)); +//.. addInstr(env, X86Instr_Test32(X86RI_Imm(0xFF), X86RM_Reg(r8))); +//.. addInstr(env, X86Instr_SseCMov(Xcc_Z,r0,dst)); +//.. return dst; +//.. } +//.. +//.. vec_fail: +//.. vex_printf("iselVecExpr (subarch = %s): can't reduce\n", +//.. LibVEX_ppVexSubArch(env->subarch)); +//.. ppIRExpr(e); +//.. vpanic("iselVecExpr_wrk"); +//.. +//.. # undef REQUIRE_SSE1 +//.. # undef REQUIRE_SSE2 +//.. } + + +/*---------------------------------------------------------*/ +/*--- ISEL: Statements ---*/ +/*---------------------------------------------------------*/ + +static void iselStmt ( ISelEnv* env, IRStmt* stmt ) +{ + if (vex_traceflags & VEX_TRACE_VCODE) { + vex_printf("\n-- "); + ppIRStmt(stmt); + vex_printf("\n"); + } + + switch (stmt->tag) { + +//.. /* --------- STORE --------- */ +//.. case Ist_STle: { +//.. X86AMode* am; +//.. IRType tya = typeOfIRExpr(env->type_env, stmt->Ist.STle.addr); +//.. IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.STle.data); +//.. vassert(tya == Ity_I32); +//.. am = iselIntExpr_AMode(env, stmt->Ist.STle.addr); +//.. if (tyd == Ity_I32) { +//.. X86RI* ri = iselIntExpr_RI(env, stmt->Ist.STle.data); +//.. addInstr(env, X86Instr_Alu32M(Xalu_MOV,ri,am)); +//.. return; +//.. } +//.. if (tyd == Ity_I8 || tyd == Ity_I16) { +//.. HReg r = iselIntExpr_R(env, stmt->Ist.STle.data); +//.. addInstr(env, X86Instr_Store(tyd==Ity_I8 ? 1 : 2, +//.. r,am)); +//.. return; +//.. } +//.. if (tyd == Ity_F64) { +//.. HReg r = iselDblExpr(env, stmt->Ist.STle.data); +//.. addInstr(env, X86Instr_FpLdSt(False/*store*/, 8, r, am)); +//.. return; +//.. } +//.. if (tyd == Ity_F32) { +//.. HReg r = iselFltExpr(env, stmt->Ist.STle.data); +//.. addInstr(env, X86Instr_FpLdSt(False/*store*/, 4, r, am)); +//.. return; +//.. } +//.. if (tyd == Ity_I64) { +//.. HReg vHi, vLo, rA; +//.. iselInt64Expr(&vHi, &vLo, env, stmt->Ist.STle.data); +//.. rA = iselIntExpr_R(env, stmt->Ist.STle.addr); +//.. addInstr(env, X86Instr_Alu32M( +//.. Xalu_MOV, X86RI_Reg(vLo), X86AMode_IR(0, rA))); +//.. addInstr(env, X86Instr_Alu32M( +//.. Xalu_MOV, X86RI_Reg(vHi), X86AMode_IR(4, rA))); +//.. return; +//.. } +//.. if (tyd == Ity_V128) { +//.. HReg r = iselVecExpr(env, stmt->Ist.STle.data); +//.. addInstr(env, X86Instr_SseLdSt(False/*store*/, r, am)); +//.. return; +//.. } +//.. break; +//.. } +//.. +//.. /* --------- PUT --------- */ +//.. case Ist_Put: { +//.. IRType ty = typeOfIRExpr(env->type_env, stmt->Ist.Put.data); +//.. if (ty == Ity_I32) { +//.. /* We're going to write to memory, so compute the RHS into an +//.. X86RI. */ +//.. X86RI* ri = iselIntExpr_RI(env, stmt->Ist.Put.data); +//.. addInstr(env, +//.. X86Instr_Alu32M( +//.. Xalu_MOV, +//.. ri, +//.. X86AMode_IR(stmt->Ist.Put.offset,hregX86_EBP()) +//.. )); +//.. return; +//.. } +//.. if (ty == Ity_I8 || ty == Ity_I16) { +//.. HReg r = iselIntExpr_R(env, stmt->Ist.Put.data); +//.. addInstr(env, X86Instr_Store( +//.. ty==Ity_I8 ? 1 : 2, +//.. r, +//.. X86AMode_IR(stmt->Ist.Put.offset, +//.. hregX86_EBP()))); +//.. return; +//.. } +//.. if (ty == Ity_I64) { +//.. HReg vHi, vLo; +//.. X86AMode* am = X86AMode_IR(stmt->Ist.Put.offset, hregX86_EBP()); +//.. X86AMode* am4 = advance4(am); +//.. iselInt64Expr(&vHi, &vLo, env, stmt->Ist.Put.data); +//.. addInstr(env, X86Instr_Alu32M( Xalu_MOV, X86RI_Reg(vLo), am )); +//.. addInstr(env, X86Instr_Alu32M( Xalu_MOV, X86RI_Reg(vHi), am4 )); +//.. return; +//.. } +//.. if (ty == Ity_V128) { +//.. HReg vec = iselVecExpr(env, stmt->Ist.Put.data); +//.. X86AMode* am = X86AMode_IR(stmt->Ist.Put.offset, hregX86_EBP()); +//.. addInstr(env, X86Instr_SseLdSt(False/*store*/, vec, am)); +//.. return; +//.. } +//.. if (ty == Ity_F32) { +//.. HReg f32 = iselFltExpr(env, stmt->Ist.Put.data); +//.. X86AMode* am = X86AMode_IR(stmt->Ist.Put.offset, hregX86_EBP()); +//.. set_FPU_rounding_default(env); /* paranoia */ +//.. addInstr(env, X86Instr_FpLdSt( False/*store*/, 4, f32, am )); +//.. return; +//.. } +//.. if (ty == Ity_F64) { +//.. HReg f64 = iselDblExpr(env, stmt->Ist.Put.data); +//.. X86AMode* am = X86AMode_IR(stmt->Ist.Put.offset, hregX86_EBP()); +//.. set_FPU_rounding_default(env); /* paranoia */ +//.. addInstr(env, X86Instr_FpLdSt( False/*store*/, 8, f64, am )); +//.. return; +//.. } +//.. break; +//.. } +//.. +//.. /* --------- Indexed PUT --------- */ +//.. case Ist_PutI: { +//.. X86AMode* am +//.. = genGuestArrayOffset( +//.. env, stmt->Ist.PutI.descr, +//.. stmt->Ist.PutI.ix, stmt->Ist.PutI.bias ); +//.. +//.. IRType ty = typeOfIRExpr(env->type_env, stmt->Ist.PutI.data); +//.. if (ty == Ity_F64) { +//.. HReg val = iselDblExpr(env, stmt->Ist.PutI.data); +//.. addInstr(env, X86Instr_FpLdSt( False/*store*/, 8, val, am )); +//.. return; +//.. } +//.. if (ty == Ity_I8) { +//.. HReg r = iselIntExpr_R(env, stmt->Ist.PutI.data); +//.. addInstr(env, X86Instr_Store( 1, r, am )); +//.. return; +//.. } +//.. if (ty == Ity_I64) { +//.. HReg rHi, rLo; +//.. X86AMode* am4 = advance4(am); +//.. iselInt64Expr(&rHi, &rLo, env, stmt->Ist.PutI.data); +//.. addInstr(env, X86Instr_Alu32M( Xalu_MOV, X86RI_Reg(rLo), am )); +//.. addInstr(env, X86Instr_Alu32M( Xalu_MOV, X86RI_Reg(rHi), am4 )); +//.. return; +//.. } +//.. break; +//.. } +//.. +//.. /* --------- TMP --------- */ +//.. case Ist_Tmp: { +//.. IRTemp tmp = stmt->Ist.Tmp.tmp; +//.. IRType ty = typeOfIRTemp(env->type_env, tmp); +//.. if (ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8) { +//.. X86RMI* rmi = iselIntExpr_RMI(env, stmt->Ist.Tmp.data); +//.. HReg dst = lookupIRTemp(env, tmp); +//.. addInstr(env, X86Instr_Alu32R(Xalu_MOV,rmi,dst)); +//.. return; +//.. } +//.. if (ty == Ity_I64) { +//.. HReg rHi, rLo, dstHi, dstLo; +//.. iselInt64Expr(&rHi,&rLo, env, stmt->Ist.Tmp.data); +//.. lookupIRTemp64( &dstHi, &dstLo, env, tmp); +//.. addInstr(env, mk_iMOVsd_RR(rHi,dstHi) ); +//.. addInstr(env, mk_iMOVsd_RR(rLo,dstLo) ); +//.. return; +//.. } +//.. if (ty == Ity_I1) { +//.. X86CondCode cond = iselCondCode(env, stmt->Ist.Tmp.data); +//.. HReg dst = lookupIRTemp(env, tmp); +//.. addInstr(env, X86Instr_Set32(cond, dst)); +//.. return; +//.. } +//.. if (ty == Ity_F64) { +//.. HReg dst = lookupIRTemp(env, tmp); +//.. HReg src = iselDblExpr(env, stmt->Ist.Tmp.data); +//.. addInstr(env, X86Instr_FpUnary(Xfp_MOV,src,dst)); +//.. return; +//.. } +//.. if (ty == Ity_F32) { +//.. HReg dst = lookupIRTemp(env, tmp); +//.. HReg src = iselFltExpr(env, stmt->Ist.Tmp.data); +//.. addInstr(env, X86Instr_FpUnary(Xfp_MOV,src,dst)); +//.. return; +//.. } +//.. if (ty == Ity_V128) { +//.. HReg dst = lookupIRTemp(env, tmp); +//.. HReg src = iselVecExpr(env, stmt->Ist.Tmp.data); +//.. addInstr(env, mk_vMOVsd_RR(src,dst)); +//.. return; +//.. } +//.. break; +//.. } +//.. +//.. /* --------- Call to DIRTY helper --------- */ +//.. case Ist_Dirty: { +//.. IRType retty; +//.. IRDirty* d = stmt->Ist.Dirty.details; +//.. Bool passBBP = False; +//.. +//.. if (d->nFxState == 0) +//.. vassert(!d->needsBBP); +//.. passBBP = d->nFxState > 0 && d->needsBBP; +//.. +//.. /* Marshal args, do the call, clear stack. */ +//.. doHelperCall( env, passBBP, d->guard, d->cee, d->args ); +//.. +//.. /* Now figure out what to do with the returned value, if any. */ +//.. if (d->tmp == IRTemp_INVALID) +//.. /* No return value. Nothing to do. */ +//.. return; +//.. +//.. retty = typeOfIRTemp(env->type_env, d->tmp); +//.. if (retty == Ity_I64) { +//.. HReg dstHi, dstLo; +//.. /* The returned value is in %edx:%eax. Park it in the +//.. register-pair associated with tmp. */ +//.. lookupIRTemp64( &dstHi, &dstLo, env, d->tmp); +//.. addInstr(env, mk_iMOVsd_RR(hregX86_EDX(),dstHi) ); +//.. addInstr(env, mk_iMOVsd_RR(hregX86_EAX(),dstLo) ); +//.. return; +//.. } +//.. if (retty == Ity_I32 || retty == Ity_I16 || retty == Ity_I8) { +//.. /* The returned value is in %eax. Park it in the register +//.. associated with tmp. */ +//.. HReg dst = lookupIRTemp(env, d->tmp); +//.. addInstr(env, mk_iMOVsd_RR(hregX86_EAX(),dst) ); +//.. return; +//.. } +//.. break; +//.. } +//.. +//.. /* --------- MEM FENCE --------- */ +//.. case Ist_MFence: +//.. addInstr(env, X86Instr_MFence(env->subarch)); +//.. return; +//.. +//.. /* --------- EXIT --------- */ +//.. case Ist_Exit: { +//.. X86RI* dst; +//.. X86CondCode cc; +//.. if (stmt->Ist.Exit.dst->tag != Ico_U32) +//.. vpanic("isel_x86: Ist_Exit: dst is not a 32-bit value"); +//.. dst = iselIntExpr_RI(env, IRExpr_Const(stmt->Ist.Exit.dst)); +//.. cc = iselCondCode(env,stmt->Ist.Exit.guard); +//.. addInstr(env, X86Instr_Goto(stmt->Ist.Exit.jk, cc, dst)); +//.. return; +//.. } + + default: break; + } + ppIRStmt(stmt); + vpanic("iselStmt"); +} + + +/*---------------------------------------------------------*/ +/*--- ISEL: Basic block terminators (Nexts) ---*/ +/*---------------------------------------------------------*/ + +static void iselNext ( ISelEnv* env, IRExpr* next, IRJumpKind jk ) +{ vassert(0); +//.. X86RI* ri; +//.. if (vex_traceflags & VEX_TRACE_VCODE) { +//.. vex_printf("\n-- goto {"); +//.. ppIRJumpKind(jk); +//.. vex_printf("} "); +//.. ppIRExpr(next); +//.. vex_printf("\n"); +//.. } +//.. ri = iselIntExpr_RI(env, next); +//.. addInstr(env, X86Instr_Goto(jk, Xcc_ALWAYS,ri)); +} + + +/*---------------------------------------------------------*/ +/*--- Insn selector top-level ---*/ +/*---------------------------------------------------------*/ + +/* Translate an entire BB to x86 code. */ + +HInstrArray* iselBB_PPC32 ( IRBB* bb, VexSubArch subarch_host ) +{ + Int i, j; + HReg hreg, hregHI; + + /* sanity ... */ + vassert(subarch_host == VexSubArchPPC32_noAV + || subarch_host == VexSubArchPPC32_AV); + + /* Make up an initial environment to use. */ + ISelEnv* env = LibVEX_Alloc(sizeof(ISelEnv)); + env->vreg_ctr = 0; + + /* Set up output code array. */ + env->code = newHInstrArray(); + + /* 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->types_used; + env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg)); + env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg)); + + /* and finally ... */ + env->subarch = subarch_host; + + /* For each IR temporary, allocate a suitably-kinded virtual + register. */ + j = 0; + for (i = 0; i < env->n_vregmap; i++) { + hregHI = hreg = INVALID_HREG; + switch (bb->tyenv->types[i]) { + case Ity_I1: + case Ity_I8: + case Ity_I16: + case Ity_I32: hreg = mkHReg(j++, HRcInt32, True); break; + case Ity_I64: hreg = mkHReg(j++, HRcInt32, True); + hregHI = mkHReg(j++, HRcInt32, True); break; + case Ity_F32: + case Ity_F64: hreg = mkHReg(j++, HRcFlt64, True); break; + case Ity_V128: hreg = mkHReg(j++, HRcVec128, True); break; + default: ppIRType(bb->tyenv->types[i]); + vpanic("iselBB(ppc32): IRTemp type"); + } + env->vregmap[i] = hreg; + env->vregmapHI[i] = hregHI; + } + env->vreg_ctr = j; + + /* Ok, finally we can iterate over the statements. */ + for (i = 0; i < bb->stmts_used; i++) + if (bb->stmts[i]) + iselStmt(env,bb->stmts[i]); + + iselNext(env,bb->next,bb->jumpkind); + + /* record the number of vregs we used. */ + env->code->n_vregs = env->vreg_ctr; + return env->code; +} + + +/*---------------------------------------------------------------*/ +/*--- end host-ppc32/isel.c ---*/ +/*---------------------------------------------------------------*/