gallivm: Use LLVM MC disassembler, instead of udis86.

Included in LLVM 2.7+. Unlink udis86, should support all instructions that
LLVM can emit.
This commit is contained in:
José Fonseca 2011-03-13 19:24:26 +00:00
parent d2332569d2
commit e6314db0ac
12 changed files with 372 additions and 281 deletions

View File

@ -12,7 +12,7 @@ GALLIUM_DRIVERS_DIRS += llvmpipe
OPT_FLAGS = -O3 -ansi -pedantic
ARCH_FLAGS = -mmmx -msse -msse2 -mstackrealign
DEFINES += -DNDEBUG -DGALLIUM_LLVMPIPE -DHAVE_UDIS86
DEFINES += -DNDEBUG -DGALLIUM_LLVMPIPE
# override -std=c99
CFLAGS += -std=gnu99
@ -41,4 +41,4 @@ else
endif
LD = g++
GL_LIB_DEPS = $(LLVM_LDFLAGS) $(LLVM_LIBS) $(EXTRA_LIB_PATH) -lX11 -lXext -lm -lpthread -lstdc++ -ludis86
GL_LIB_DEPS = $(LLVM_LDFLAGS) $(LLVM_LIBS) $(EXTRA_LIB_PATH) -lX11 -lXext -lm -lpthread -lstdc++

View File

@ -1400,8 +1400,6 @@ if test "x$enable_gallium" = xno -a "x$enable_openvg" = xyes; then
fi
if test "x$enable_gallium" = xyes; then
SRC_DIRS="$SRC_DIRS gallium gallium/winsys gallium/targets"
AC_CHECK_HEADER([udis86.h], [HAS_UDIS86="yes"],
[HAS_UDIS86="no"])
AC_PATH_PROG([LLVM_CONFIG], [llvm-config], [no])
fi
@ -1653,10 +1651,6 @@ if test "x$enable_gallium_llvm" = xyes; then
LLVM_CFLAGS=`$LLVM_CONFIG --cppflags`
LLVM_LIBS="`$LLVM_CONFIG --libs jit interpreter nativecodegen bitwriter` -lstdc++"
if test "x$HAS_UDIS86" != xno; then
LLVM_LIBS="$LLVM_LIBS -ludis86"
DEFINES="$DEFINES -DHAVE_UDIS86"
fi
LLVM_LDFLAGS=`$LLVM_CONFIG --ldflags`
GALLIUM_DRIVERS_DIRS="$GALLIUM_DRIVERS_DIRS llvmpipe"
DEFINES="$DEFINES -DGALLIUM_LLVMPIPE -D__STDC_CONSTANT_MACROS"

View File

@ -602,7 +602,6 @@ def generate(env):
env.Tool('yacc')
if env['llvm']:
env.Tool('llvm')
env.Tool('udis86')
pkg_config_modules(env, 'x11', ['x11', 'xext'])
pkg_config_modules(env, 'drm', ['libdrm'])

View File

@ -142,7 +142,7 @@ def generate(env):
try:
env.ParseConfig('llvm-config --cppflags')
env.ParseConfig('llvm-config --libs jit interpreter nativecodegen bitwriter')
env.ParseConfig('llvm-config --libs')
env.ParseConfig('llvm-config --ldflags')
except OSError:
print 'scons: llvm-config version %s failed' % llvm_version

View File

@ -1,44 +0,0 @@
"""udis86
Tool-specific initialization for udis86
"""
#
# Copyright (c) 2009 VMware, Inc.
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
def generate(env):
conf = env.Configure()
if conf.CheckHeader('udis86.h'): # and conf.CheckLib('udis86'):
env['UDIS86'] = True
env.Prepend(LIBS = ['udis86'])
else:
env['UDIS86'] = False
conf.Finish()
def exists(env):
return True
# vim:set ts=4 sw=4 et:

View File

@ -161,7 +161,6 @@ GALLIVM_SOURCES = \
gallivm/lp_bld_bitarit.c \
gallivm/lp_bld_const.c \
gallivm/lp_bld_conv.c \
gallivm/lp_bld_debug.c \
gallivm/lp_bld_flow.c \
gallivm/lp_bld_format_aos.c \
gallivm/lp_bld_format_soa.c \
@ -189,6 +188,7 @@ GALLIVM_SOURCES = \
draw/draw_pt_fetch_shade_pipeline_llvm.c
GALLIVM_CPP_SOURCES = \
gallivm/lp_bld_debug.cpp \
gallivm/lp_bld_misc.cpp
GENERATED_SOURCES = \

View File

@ -203,16 +203,13 @@ source = [
]
if env['llvm']:
if env['UDIS86']:
env.Append(CPPDEFINES = [('HAVE_UDIS86', '1')])
source += [
'gallivm/lp_bld_arit.c',
'gallivm/lp_bld_assert.c',
'gallivm/lp_bld_bitarit.c',
'gallivm/lp_bld_const.c',
'gallivm/lp_bld_conv.c',
'gallivm/lp_bld_debug.c',
'gallivm/lp_bld_debug.cpp',
'gallivm/lp_bld_flow.c',
'gallivm/lp_bld_format_aos.c',
'gallivm/lp_bld_format_soa.c',

View File

@ -1,141 +0,0 @@
/**************************************************************************
*
* Copyright 2009 VMware, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
#ifdef HAVE_UDIS86
#include <udis86.h>
#endif
#include "util/u_math.h"
#include "util/u_debug.h"
#include "lp_bld_debug.h"
/**
* Check alignment.
*
* It is important that this check is not implemented as a macro or inlined
* function, as the compiler assumptions in respect to alignment of global
* and stack variables would often make the check a no op, defeating the
* whole purpose of the exercise.
*/
boolean
lp_check_alignment(const void *ptr, unsigned alignment)
{
assert(util_is_power_of_two(alignment));
return ((uintptr_t)ptr & (alignment - 1)) == 0;
}
void
lp_disassemble(const void* func)
{
#ifdef HAVE_UDIS86
ud_t ud_obj;
uint64_t max_jmp_pc;
uint inst_no;
boolean emit_addrs = TRUE, emit_line_nos = FALSE;
ud_init(&ud_obj);
ud_set_input_buffer(&ud_obj, (void*)func, 0xffff);
max_jmp_pc = (uint64_t) (uintptr_t) func;
ud_set_pc(&ud_obj, max_jmp_pc);
#ifdef PIPE_ARCH_X86
ud_set_mode(&ud_obj, 32);
#endif
#ifdef PIPE_ARCH_X86_64
ud_set_mode(&ud_obj, 64);
#endif
ud_set_syntax(&ud_obj, UD_SYN_ATT);
while (ud_disassemble(&ud_obj)) {
if (emit_addrs) {
#ifdef PIPE_ARCH_X86
debug_printf("0x%08lx:\t", (unsigned long)ud_insn_off(&ud_obj));
#endif
#ifdef PIPE_ARCH_X86_64
debug_printf("0x%016llx:\t", (unsigned long long)ud_insn_off(&ud_obj));
#endif
}
else if (emit_line_nos) {
debug_printf("%6d:\t", inst_no);
inst_no++;
}
#if 0
debug_printf("%-16s ", ud_insn_hex(&ud_obj));
#endif
debug_printf("%s\n", ud_insn_asm(&ud_obj));
if(ud_obj.mnemonic != UD_Icall) {
unsigned i;
for(i = 0; i < 3; ++i) {
const struct ud_operand *op = &ud_obj.operand[i];
if (op->type == UD_OP_JIMM){
uint64_t pc = ud_obj.pc;
switch (op->size) {
case 8:
pc += op->lval.sbyte;
break;
case 16:
pc += op->lval.sword;
break;
case 32:
pc += op->lval.sdword;
break;
default:
break;
}
if(pc > max_jmp_pc)
max_jmp_pc = pc;
}
}
}
if (ud_obj.mnemonic == UD_Iinvalid ||
(ud_insn_off(&ud_obj) >= max_jmp_pc &&
(ud_obj.mnemonic == UD_Iret ||
ud_obj.mnemonic == UD_Ijmp)))
break;
}
#if 0
/* Print GDB command, useful to verify udis86 output */
debug_printf("disassemble %p %p\n", func, (void*)(uintptr_t)ud_obj.pc);
#endif
debug_printf("\n");
#else
(void)func;
#endif
}

View File

@ -0,0 +1,355 @@
/**************************************************************************
*
* Copyright 2009-2011 VMware, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
#include <llvm-c/Core.h>
#include <llvm/Target/TargetMachine.h>
#include <llvm/Target/TargetRegistry.h>
#include <llvm/Target/TargetSelect.h>
#include <llvm/Target/TargetInstrInfo.h>
#include <llvm/Support/raw_ostream.h>
#include <llvm/Support/MemoryObject.h>
#include <llvm/System/Host.h>
#if HAVE_LLVM >= 0x0207
#include <llvm/MC/MCDisassembler.h>
#include <llvm/MC/MCAsmInfo.h>
#include <llvm/MC/MCInst.h>
#include <llvm/MC/MCInstPrinter.h>
#endif /* HAVE_LLVM >= 0x0207 */
#include "util/u_math.h"
#include "util/u_debug.h"
#include "lp_bld_debug.h"
/**
* Check alignment.
*
* It is important that this check is not implemented as a macro or inlined
* function, as the compiler assumptions in respect to alignment of global
* and stack variables would often make the check a no op, defeating the
* whole purpose of the exercise.
*/
extern "C" boolean
lp_check_alignment(const void *ptr, unsigned alignment)
{
assert(util_is_power_of_two(alignment));
return ((uintptr_t)ptr & (alignment - 1)) == 0;
}
class raw_debug_ostream :
public llvm::raw_ostream
{
uint64_t pos;
void write_impl(const char *Ptr, size_t Size);
uint64_t current_pos() { return pos; }
uint64_t current_pos() const { return pos; }
#if HAVE_LLVM >= 0x207
uint64_t preferred_buffer_size() { return 512; }
#else
size_t preferred_buffer_size() { return 512; }
#endif
};
void
raw_debug_ostream::write_impl(const char *Ptr, size_t Size)
{
if (Size > 0) {
char *lastPtr = (char *)&Ptr[Size];
char last = *lastPtr;
*lastPtr = 0;
_debug_printf("%*s", Size, Ptr);
*lastPtr = last;
pos += Size;
}
}
/**
* Same as LLVMDumpValue, but through our debugging channels.
*/
extern "C" void
lp_debug_dump_value(LLVMValueRef value)
{
#if (defined(PIPE_OS_WINDOWS) && !defined(PIPE_CC_MSVC)) || defined(PIPE_OS_EMBDDED)
raw_debug_ostream os;
llvm::unwrap(value)->print(os);
os.flush();
#else
LLVMDumpValue(value);
#endif
}
/*
* MemoryObject wrapper around a buffer of memory, to be used by MC
* disassembler.
*/
class BufferMemoryObject:
public llvm::MemoryObject
{
private:
const uint8_t *Bytes;
uint64_t Length;
public:
BufferMemoryObject(const uint8_t *bytes, uint64_t length) :
Bytes(bytes), Length(length)
{
}
uint64_t getBase() const
{
return 0;
}
uint64_t getExtent() const
{
return Length;
}
int readByte(uint64_t addr, uint8_t *byte) const
{
if (addr > getExtent())
return -1;
*byte = Bytes[addr];
return 0;
}
};
/*
* Disassemble a function, using the LLVM MC disassembler.
*
* See also:
* - http://blog.llvm.org/2010/01/x86-disassembler.html
* - http://blog.llvm.org/2010/04/intro-to-llvm-mc-project.html
*/
extern "C" void
lp_disassemble(const void* func)
{
#if HAVE_LLVM >= 0x0207
using namespace llvm;
const uint8_t *bytes = (const uint8_t *)func;
/*
* Limit disassembly to this extent
*/
const uint64_t extent = 0x10000;
uint64_t max_pc = 0;
/*
* Initialize all used objects.
*/
std::string Triple = sys::getHostTriple();
std::string Error;
const Target *T = TargetRegistry::lookupTarget(Triple, Error);
#if HAVE_LLVM >= 0x0208
InitializeNativeTargetAsmPrinter();
#else
InitializeAllAsmPrinters();
#endif
InitializeAllDisassemblers();
OwningPtr<const MCAsmInfo> AsmInfo(T->createAsmInfo(Triple));
if (!AsmInfo) {
debug_printf("error: no assembly info for target %s\n", Triple.c_str());
return;
}
OwningPtr<const MCDisassembler> DisAsm(T->createMCDisassembler());
if (!DisAsm) {
debug_printf("error: no disassembler for target %s\n", Triple.c_str());
return;
}
raw_debug_ostream Out;
int AsmPrinterVariant = AsmInfo->getAssemblerDialect();
#if HAVE_LLVM >= 0x0208
OwningPtr<MCInstPrinter> Printer(
T->createMCInstPrinter(AsmPrinterVariant, *AsmInfo));
#else
OwningPtr<MCInstPrinter> Printer(
T->createMCInstPrinter(AsmPrinterVariant, *AsmInfo, Out));
#endif
if (!Printer) {
debug_printf("error: no instruction printer for target %s\n", Triple.c_str());
return;
}
TargetMachine *TM = T->createTargetMachine(Triple, "");
const TargetInstrInfo *TII = TM->getInstrInfo();
/*
* Wrap the data in a MemoryObject
*/
BufferMemoryObject memoryObject((const uint8_t *)bytes, extent);
uint64_t pc;
pc = 0;
while (true) {
MCInst Inst;
uint64_t Size;
/*
* Print address. We use addresses relative to the start of the function,
* so that between runs.
*/
debug_printf("%6lu:\t", (unsigned long)pc);
if (!DisAsm->getInstruction(Inst, Size, memoryObject,
pc,
nulls())) {
debug_printf("invalid\n");
pc += 1;
}
/*
* Output the bytes in hexidecimal format.
*/
if (0) {
unsigned i;
for (i = 0; i < Size; ++i) {
debug_printf("%02x ", ((const uint8_t*)bytes)[pc + i]);
}
for (; i < 16; ++i) {
debug_printf(" ");
}
}
/*
* Print the instruction.
*/
#if HAVE_LLVM >= 0x208
Printer->printInst(&Inst, Out);
#else
Printer->printInst(&Inst);
#endif
Out.flush();
/*
* Advance.
*/
pc += Size;
const TargetInstrDesc &TID = TII->get(Inst.getOpcode());
/*
* Keep track of forward jumps to a nearby address.
*/
if (TID.isBranch()) {
for (unsigned i = 0; i < Inst.getNumOperands(); ++i) {
const MCOperand &operand = Inst.getOperand(i);
if (operand.isImm()) {
uint64_t jump;
/*
* FIXME: Handle both relative and absolute addresses correctly.
* EDInstInfo actually has this info, but operandTypes and
* operandFlags enums are not exposed in the public interface.
*/
if (1) {
/*
* PC relative addr.
*/
jump = pc + operand.getImm();
} else {
/*
* Absolute addr.
*/
jump = (uint64_t)operand.getImm();
}
/*
* Output the address relative to the function start, given
* that MC will print the addresses relative the current pc.
*/
debug_printf("\t\t; %lu", (unsigned long)jump);
/*
* Ignore far jumps given it could be actually a tail return to
* a random address.
*/
if (jump > max_pc &&
jump < extent) {
max_pc = jump;
}
}
}
}
debug_printf("\n");
/*
* Stop disassembling on return statements, if there is no record of a
* jump to a successive address.
*/
if (TID.isReturn()) {
if (pc > max_pc) {
break;
}
}
}
/*
* Print GDB command, useful to verify output.
*/
if (0) {
debug_printf("disassemble %p %p\n", bytes, bytes + pc);
}
debug_printf("\n");
#else
(void)func;
#endif
}

View File

@ -45,6 +45,11 @@
#define GALLIVM_DEBUG_GC (1 << 6)
#ifdef __cplusplus
extern "C" {
#endif
#ifdef DEBUG
extern unsigned gallivm_debug;
#else
@ -81,4 +86,9 @@ void
lp_disassemble(const void* func);
#ifdef __cplusplus
}
#endif
#endif /* !LP_BLD_DEBUG_H */

View File

@ -46,66 +46,6 @@
#include "util/u_debug.h"
#if (defined(PIPE_OS_WINDOWS) && !defined(PIPE_CC_MSVC)) || defined(PIPE_OS_EMBDDED)
#include "llvm/Support/raw_ostream.h"
class raw_debug_ostream :
public llvm::raw_ostream
{
uint64_t pos;
void write_impl(const char *Ptr, size_t Size);
uint64_t current_pos() { return pos; }
uint64_t current_pos() const { return pos; }
#if HAVE_LLVM >= 0x207
uint64_t preferred_buffer_size() { return 512; }
#else
size_t preferred_buffer_size() { return 512; }
#endif
};
void
raw_debug_ostream::write_impl(const char *Ptr, size_t Size)
{
if (Size > 0) {
char *lastPtr = (char *)&Ptr[Size];
char last = *lastPtr;
*lastPtr = 0;
_debug_printf("%*s", Size, Ptr);
*lastPtr = last;
pos += Size;
}
}
/**
* Same as LLVMDumpValue, but through our debugging channels.
*/
extern "C" void
lp_debug_dump_value(LLVMValueRef value)
{
raw_debug_ostream os;
llvm::unwrap(value)->print(os);
os.flush();
}
#else
extern "C" void
lp_debug_dump_value(LLVMValueRef value)
{
LLVMDumpValue(value);
}
#endif
/**
* Register the engine with oprofile.
*

View File

@ -12,7 +12,7 @@ Requirements
See /proc/cpuinfo to know what your CPU supports.
- LLVM 2.6 (or later)
- LLVM. Version 2.8 recommended. 2.6 or later required.
For Linux, on a recent Debian based distribution do:
@ -30,21 +30,8 @@ Requirements
debug=no. This is necessary as LLVM builds as static library so the chosen
MS CRT must match.
The version of LLVM from SVN ("2.7svn") from mid-March 2010 is pretty
stable and has some features not in version 2.6.
- scons (optional)
- udis86, http://udis86.sourceforge.net/ (optional). My personal repository
supports more opcodes which haven't been merged upstream yet:
git clone git://anongit.freedesktop.org/~jrfonseca/udis86
cd udis86
./autogen.sh
./configure --with-pic
make
sudo make install
Building
========
@ -94,13 +81,7 @@ that no tail call optimizations are done by gcc.
To better profile JIT code you'll need to build LLVM with oprofile integration.
source_dir=$PWD/llvm-2.6
build_dir=$source_dir/build/profile
install_dir=$source_dir-profile
mkdir -p "$build_dir"
cd "$build_dir" && \
$source_dir/configure \
./configure \
--prefix=$install_dir \
--enable-optimized \
--disable-profiling \