parent
8c6387facf
commit
1621ac50ab
@ -0,0 +1,44 @@
|
||||
project(mir)
|
||||
|
||||
enable_language(C)
|
||||
|
||||
message(STATUS "OS type is ${CMAKE_SYSTEM_NAME}")
|
||||
message(STATUS "System processor is ${CMAKE_HOST_SYSTEM_PROCESSOR}")
|
||||
message(STATUS "Build type is ${CMAKE_BUILD_TYPE}")
|
||||
|
||||
set(TARGET x86_64)
|
||||
|
||||
set(MIR_HEADERS
|
||||
mir.h
|
||||
mir-gen.h
|
||||
mir-varr.h
|
||||
mir-dlist.h
|
||||
mir-htab.h
|
||||
mir-hash.h
|
||||
mir-bitmap.h
|
||||
)
|
||||
|
||||
set(MIR_SRCS
|
||||
mir.c
|
||||
mir-gen.c
|
||||
)
|
||||
|
||||
set(C2MIR_SRCS
|
||||
c2mir/c2mir.c
|
||||
)
|
||||
|
||||
set(LIBS dl)
|
||||
|
||||
add_definitions(-D${TARGET})
|
||||
add_definitions(-DMIR_IO)
|
||||
add_definitions(-DMIR_SCAN)
|
||||
|
||||
include_directories(".")
|
||||
include_directories("./c2mir")
|
||||
|
||||
add_library(c2mir
|
||||
${MIR_HEADERS}
|
||||
${MIR_SRCS}
|
||||
${C2MIR_SRCS})
|
||||
target_link_libraries(c2mir ${LIBS})
|
||||
|
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Vladimir Makarov
|
||||
|
||||
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.
|
@ -0,0 +1,202 @@
|
||||
# CMAKE generated file: DO NOT EDIT!
|
||||
# Generated by "Unix Makefiles" Generator, CMake Version 3.9
|
||||
|
||||
# Default target executed when no arguments are given to make.
|
||||
default_target: all
|
||||
|
||||
.PHONY : default_target
|
||||
|
||||
# Allow only one "make -f Makefile2" at a time, but pass parallelism.
|
||||
.NOTPARALLEL:
|
||||
|
||||
|
||||
#=============================================================================
|
||||
# Special targets provided by cmake.
|
||||
|
||||
# Disable implicit rules so canonical targets will work.
|
||||
.SUFFIXES:
|
||||
|
||||
|
||||
# Remove some rules from gmake that .SUFFIXES does not remove.
|
||||
SUFFIXES =
|
||||
|
||||
.SUFFIXES: .hpux_make_needs_suffix_list
|
||||
|
||||
|
||||
# Suppress display of executed commands.
|
||||
$(VERBOSE).SILENT:
|
||||
|
||||
|
||||
# A target that is always out of date.
|
||||
cmake_force:
|
||||
|
||||
.PHONY : cmake_force
|
||||
|
||||
#=============================================================================
|
||||
# Set environment variables for the build.
|
||||
|
||||
# The shell in which to execute make rules.
|
||||
SHELL = /bin/sh
|
||||
|
||||
# The CMake executable.
|
||||
CMAKE_COMMAND = /Applications/CMake.app/Contents/bin/cmake
|
||||
|
||||
# The command to remove a file.
|
||||
RM = /Applications/CMake.app/Contents/bin/cmake -E remove -f
|
||||
|
||||
# Escaping for special characters.
|
||||
EQUALS = =
|
||||
|
||||
# The top-level source directory on which CMake was run.
|
||||
CMAKE_SOURCE_DIR = /Users/dylan/github/ravi/mir
|
||||
|
||||
# The top-level build directory on which CMake was run.
|
||||
CMAKE_BINARY_DIR = /Users/dylan/github/ravi/mir/build
|
||||
|
||||
#=============================================================================
|
||||
# Targets provided globally by CMake.
|
||||
|
||||
# Special rule for the target rebuild_cache
|
||||
rebuild_cache:
|
||||
@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..."
|
||||
/Applications/CMake.app/Contents/bin/cmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)
|
||||
.PHONY : rebuild_cache
|
||||
|
||||
# Special rule for the target rebuild_cache
|
||||
rebuild_cache/fast: rebuild_cache
|
||||
|
||||
.PHONY : rebuild_cache/fast
|
||||
|
||||
# Special rule for the target edit_cache
|
||||
edit_cache:
|
||||
@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake cache editor..."
|
||||
/Applications/CMake.app/Contents/bin/ccmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)
|
||||
.PHONY : edit_cache
|
||||
|
||||
# Special rule for the target edit_cache
|
||||
edit_cache/fast: edit_cache
|
||||
|
||||
.PHONY : edit_cache/fast
|
||||
|
||||
# The main all target
|
||||
all: cmake_check_build_system
|
||||
$(CMAKE_COMMAND) -E cmake_progress_start /Users/dylan/github/ravi/mir/build/CMakeFiles /Users/dylan/github/ravi/mir/build/CMakeFiles/progress.marks
|
||||
$(MAKE) -f CMakeFiles/Makefile2 all
|
||||
$(CMAKE_COMMAND) -E cmake_progress_start /Users/dylan/github/ravi/mir/build/CMakeFiles 0
|
||||
.PHONY : all
|
||||
|
||||
# The main clean target
|
||||
clean:
|
||||
$(MAKE) -f CMakeFiles/Makefile2 clean
|
||||
.PHONY : clean
|
||||
|
||||
# The main clean target
|
||||
clean/fast: clean
|
||||
|
||||
.PHONY : clean/fast
|
||||
|
||||
# Prepare targets for installation.
|
||||
preinstall: all
|
||||
$(MAKE) -f CMakeFiles/Makefile2 preinstall
|
||||
.PHONY : preinstall
|
||||
|
||||
# Prepare targets for installation.
|
||||
preinstall/fast:
|
||||
$(MAKE) -f CMakeFiles/Makefile2 preinstall
|
||||
.PHONY : preinstall/fast
|
||||
|
||||
# clear depends
|
||||
depend:
|
||||
$(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1
|
||||
.PHONY : depend
|
||||
|
||||
#=============================================================================
|
||||
# Target rules for targets named c2mir
|
||||
|
||||
# Build rule for target.
|
||||
c2mir: cmake_check_build_system
|
||||
$(MAKE) -f CMakeFiles/Makefile2 c2mir
|
||||
.PHONY : c2mir
|
||||
|
||||
# fast build rule for target.
|
||||
c2mir/fast:
|
||||
$(MAKE) -f CMakeFiles/c2mir.dir/build.make CMakeFiles/c2mir.dir/build
|
||||
.PHONY : c2mir/fast
|
||||
|
||||
# target to build an object file
|
||||
c2mir/c2mir.o:
|
||||
$(MAKE) -f CMakeFiles/c2mir.dir/build.make CMakeFiles/c2mir.dir/c2mir/c2mir.o
|
||||
.PHONY : c2mir/c2mir.o
|
||||
|
||||
# target to preprocess a source file
|
||||
c2mir/c2mir.i:
|
||||
$(MAKE) -f CMakeFiles/c2mir.dir/build.make CMakeFiles/c2mir.dir/c2mir/c2mir.i
|
||||
.PHONY : c2mir/c2mir.i
|
||||
|
||||
# target to generate assembly for a file
|
||||
c2mir/c2mir.s:
|
||||
$(MAKE) -f CMakeFiles/c2mir.dir/build.make CMakeFiles/c2mir.dir/c2mir/c2mir.s
|
||||
.PHONY : c2mir/c2mir.s
|
||||
|
||||
# target to build an object file
|
||||
mir-gen.o:
|
||||
$(MAKE) -f CMakeFiles/c2mir.dir/build.make CMakeFiles/c2mir.dir/mir-gen.o
|
||||
.PHONY : mir-gen.o
|
||||
|
||||
# target to preprocess a source file
|
||||
mir-gen.i:
|
||||
$(MAKE) -f CMakeFiles/c2mir.dir/build.make CMakeFiles/c2mir.dir/mir-gen.i
|
||||
.PHONY : mir-gen.i
|
||||
|
||||
# target to generate assembly for a file
|
||||
mir-gen.s:
|
||||
$(MAKE) -f CMakeFiles/c2mir.dir/build.make CMakeFiles/c2mir.dir/mir-gen.s
|
||||
.PHONY : mir-gen.s
|
||||
|
||||
# target to build an object file
|
||||
mir.o:
|
||||
$(MAKE) -f CMakeFiles/c2mir.dir/build.make CMakeFiles/c2mir.dir/mir.o
|
||||
.PHONY : mir.o
|
||||
|
||||
# target to preprocess a source file
|
||||
mir.i:
|
||||
$(MAKE) -f CMakeFiles/c2mir.dir/build.make CMakeFiles/c2mir.dir/mir.i
|
||||
.PHONY : mir.i
|
||||
|
||||
# target to generate assembly for a file
|
||||
mir.s:
|
||||
$(MAKE) -f CMakeFiles/c2mir.dir/build.make CMakeFiles/c2mir.dir/mir.s
|
||||
.PHONY : mir.s
|
||||
|
||||
# Help Target
|
||||
help:
|
||||
@echo "The following are some of the valid targets for this Makefile:"
|
||||
@echo "... all (the default if no target is provided)"
|
||||
@echo "... clean"
|
||||
@echo "... depend"
|
||||
@echo "... rebuild_cache"
|
||||
@echo "... edit_cache"
|
||||
@echo "... c2mir"
|
||||
@echo "... c2mir/c2mir.o"
|
||||
@echo "... c2mir/c2mir.i"
|
||||
@echo "... c2mir/c2mir.s"
|
||||
@echo "... mir-gen.o"
|
||||
@echo "... mir-gen.i"
|
||||
@echo "... mir-gen.s"
|
||||
@echo "... mir.o"
|
||||
@echo "... mir.i"
|
||||
@echo "... mir.s"
|
||||
.PHONY : help
|
||||
|
||||
|
||||
|
||||
#=============================================================================
|
||||
# Special targets to cleanup operation of make.
|
||||
|
||||
# Special rule to run CMake to check the build system integrity.
|
||||
# No rule that depends on this can have commands that come from listfiles
|
||||
# because they might be regenerated.
|
||||
cmake_check_build_system:
|
||||
$(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0
|
||||
.PHONY : cmake_check_build_system
|
||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,25 @@
|
||||
#include "mir.h"
|
||||
|
||||
#define COMMAND_LINE_SOURCE_NAME "<command-line>"
|
||||
#define STDIN_SOURCE_NAME "<stdin>"
|
||||
|
||||
struct c2mir_macro_command {
|
||||
int def_p; /* #define or #undef */
|
||||
const char *name, *def; /* def is used only when def_p is true */
|
||||
};
|
||||
|
||||
struct c2mir_options {
|
||||
FILE *message_file;
|
||||
int debug_p, verbose_p, no_prepro_p, prepro_only_p, syntax_only_p, pedantic_p, asm_p, object_p;
|
||||
size_t module_num;
|
||||
FILE *prepro_output_file; /* non-null for prepro_only_p */
|
||||
const char *output_file_name;
|
||||
size_t macro_commands_num, include_dirs_num;
|
||||
struct c2mir_macro_command *macro_commands;
|
||||
const char **include_dirs;
|
||||
};
|
||||
|
||||
void c2mir_init (MIR_context_t ctx);
|
||||
void c2mir_finish (MIR_context_t ctx);
|
||||
int c2mir_compile (MIR_context_t ctx, struct c2mir_options *ops, int (*getc_func) (void),
|
||||
const char *source_name, FILE *output_file);
|
@ -0,0 +1,22 @@
|
||||
static const char mirc[]
|
||||
= "#define __mirc__ 1\n"
|
||||
"#define __STDC_HOSTED__ 1\n"
|
||||
"//#define __STDC_ISO_10646__ 201103L\n"
|
||||
"#define __STDC_NO_ATOMICS__ 1\n"
|
||||
"#define __STDC_NO_COMPLEX__ 1\n"
|
||||
"#define __STDC_NO_THREADS__ 1\n"
|
||||
"#define __STDC_NO_VLA__ 1\n"
|
||||
"#define __STDC_UTF_16__ 1\n"
|
||||
"#define __STDC_UTF_32__ 1\n"
|
||||
"#define __STDC_VERSION__ 201112L\n"
|
||||
"#define __STDC__ 1\n"
|
||||
"\n"
|
||||
"/* Some GCC alternative keywords used but not defined in standard headers: */\n"
|
||||
"#define __const const\n"
|
||||
"#define __const__ const\n"
|
||||
"#define __inline__ inline\n"
|
||||
"#define __restrict__ restrict\n"
|
||||
"#define __signed signed\n"
|
||||
"#define __signed__ signed\n"
|
||||
"#define __volatile volatile\n"
|
||||
"#define __volatile__ volatile\n";
|
@ -0,0 +1,24 @@
|
||||
/* This file is a part of MIR project.
|
||||
Copyright (C) 2018, 2019 Vladimir Makarov <vmakarov.gcc@gmail.com>.
|
||||
*/
|
||||
|
||||
#include "../mirc.h"
|
||||
#include "mirc-x86_64-linux.h"
|
||||
|
||||
static const char *standard_includes[] = {mirc, x86_64_mirc};
|
||||
|
||||
static const char *standard_include_dirs[] = {"include/mirc/", "include/mirc/x86-64/"};
|
||||
|
||||
#define MAX_ALIGNMENT 16
|
||||
|
||||
#define ADJUST_VAR_ALIGNMENT(c2m_ctx, align, type) x86_adjust_var_alignment (c2m_ctx, align, type)
|
||||
|
||||
static int x86_adjust_var_alignment (c2m_ctx_t c2m_ctx, int align, struct type *type) {
|
||||
/* see https://www.uclibc.org/docs/psABI-x86_64.pdf */
|
||||
if (type->mode == TM_ARR && raw_type_size (c2m_ctx, type) >= 16) return 16;
|
||||
return align;
|
||||
}
|
||||
|
||||
static int invalid_alignment (mir_llong align) {
|
||||
return align != 0 && align != 1 && align != 2 && align != 4 && align != 8 && align != 16;
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/* This file is a part of MIR project.
|
||||
Copyright (C) 2018, 2019 Vladimir Makarov <vmakarov.gcc@gmail.com>.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define MIR_CHAR_BIT 8
|
||||
|
||||
typedef int8_t mir_schar;
|
||||
typedef int16_t mir_short;
|
||||
typedef int32_t mir_int;
|
||||
typedef int64_t mir_long;
|
||||
typedef int64_t mir_llong;
|
||||
|
||||
#define MIR_SCHAR_MIN INT8_MIN
|
||||
#define MIR_SCHAR_MAX INT8_MAX
|
||||
#define MIR_SHORT_MIN INT16_MIN
|
||||
#define MIR_SHORT_MAX INT16_MAX
|
||||
#define MIR_INT_MIN INT32_MIN
|
||||
#define MIR_INT_MAX INT32_MAX
|
||||
#define MIR_LONG_MIN INT64_MIN
|
||||
#define MIR_LONG_MAX INT64_MAX
|
||||
#define MIR_LLONG_MIN INT64_MIN
|
||||
#define MIR_LLONG_MAX INT64_MAX
|
||||
|
||||
typedef uint8_t mir_uchar;
|
||||
typedef uint16_t mir_ushort;
|
||||
typedef uint32_t mir_uint;
|
||||
typedef uint64_t mir_ulong;
|
||||
typedef uint64_t mir_ullong;
|
||||
|
||||
#define MIR_UCHAR_MAX UINT8_MAX
|
||||
#define MIR_USHORT_MAX UINT16_MAX
|
||||
#define MIR_UINT_MAX UINT32_MAX
|
||||
#define MIR_ULONG_MAX UINT64_MAX
|
||||
#define MIR_ULLONG_MAX UINT64_MAX
|
||||
|
||||
typedef mir_schar mir_char;
|
||||
#define MIR_CHAR_MIN MIR_SCHAR_MIN
|
||||
#define MIR_CHAR_MAX MIR_SCHAR_MAX
|
||||
|
||||
typedef float mir_float;
|
||||
typedef double mir_double;
|
||||
typedef long double mir_ldouble;
|
||||
|
||||
typedef uint8_t mir_bool;
|
||||
typedef int64_t mir_ptrdiff_t;
|
||||
typedef uint64_t mir_size_t;
|
||||
|
||||
#define MIR_SIZE_MAX UINT64_MAX
|
@ -0,0 +1,89 @@
|
||||
static char x86_64_mirc[]
|
||||
= "#define __amd64 1\n"
|
||||
"#define __amd64__ 1\n"
|
||||
"#define _LP64 1\n"
|
||||
"#define __LP64__ 1\n"
|
||||
"#define __x86_64 1\n"
|
||||
"#define __x86_64__ 1\n"
|
||||
"\n"
|
||||
"#define __SIZEOF_DOUBLE__ 8\n"
|
||||
"#define __SIZEOF_FLOAT__ 4\n"
|
||||
"#define __SIZEOF_INT__ 4\n"
|
||||
"#define __SIZEOF_LONG_DOUBLE__ 8\n"
|
||||
"#define __SIZEOF_LONG_LONG__ 8\n"
|
||||
"#define __SIZEOF_LONG__ 8\n"
|
||||
"#define __SIZEOF_POINTER__ 8\n"
|
||||
"#define __SIZEOF_PTRDIFF_T__ 8\n"
|
||||
"#define __SIZEOF_SHORT__ 2\n"
|
||||
"#define __SIZEOF_SIZE_T__ 8\n"
|
||||
"\n"
|
||||
"#define __BYTE_ORDER__ 1234\n"
|
||||
"#define __ORDER_LITTLE_ENDIAN__ 1234\n"
|
||||
"#define __ORDER_BIG_ENDIAN__ 4321\n"
|
||||
"\n"
|
||||
"/* Some GCC predefined macros: */\n"
|
||||
"#define __SIZE_TYPE__ unsigned long\n"
|
||||
"#define __PTRDIFF_TYPE__ long\n"
|
||||
"#define __INTMAX_TYPE__ long\n"
|
||||
"#define __UINTMAX_TYPE__ unsigned long\n"
|
||||
"#define __INT8_TYPE__ signed char\n"
|
||||
"#define __INT16_TYPE__ short\n"
|
||||
"#define __INT32_TYPE__ int\n"
|
||||
"#define __INT64_TYPE__ long\n"
|
||||
"#define __UINT8_TYPE__ unsigned char\n"
|
||||
"#define __UINT16_TYPE__ unsigned short\n"
|
||||
"#define __UINT32_TYPE__ unsigned int\n"
|
||||
"#define __UINT64_TYPE__ unsigned long\n"
|
||||
"#define __INTPTR_TYPE__ long\n"
|
||||
"#define __UINTPTR_TYPE__ unsigned long\n"
|
||||
"\n"
|
||||
"#define __CHAR_BIT__ 8\n"
|
||||
"#define __INT8_MAX__ 127\n"
|
||||
"#define __INT16_MAX__ 32767\n"
|
||||
"#define __INT32_MAX__ 2147483647\n"
|
||||
"#define __INT64_MAX__ 9223372036854775807l\n"
|
||||
"#define __UINT8_MAX__ (__INT8_MAX__ * 2u + 1u)\n"
|
||||
"#define __UINT16_MAX__ (__INT16_MAX__ * 2u + 1u)\n"
|
||||
"#define __UINT32_MAX__ (__INT32_MAX__ * 2u + 1u)\n"
|
||||
"#define __UINT64_MAX__ (__INT64_MAX__ * 2u + 1u)\n"
|
||||
"#define __SCHAR_MAX__ __INT8_MAX__\n"
|
||||
"#define __SHRT_MAX__ __INT16_MAX__\n"
|
||||
"#define __INT_MAX__ __INT32_MAX__\n"
|
||||
"#define __LONG_MAX__ __INT64_MAX__\n"
|
||||
"#define __LONG_LONG_MAX__ __INT64_MAX__\n"
|
||||
"#define __SIZE_MAX__ __UINT64_MAX__\n"
|
||||
"#define __PTRDIFF_MAX__ __INT64_MAX__\n"
|
||||
"#define __INTMAX_MAX__ __INT64_MAX__\n"
|
||||
"#define __UINTMAX_MAX__ __UINT64_MAX__\n"
|
||||
"#define __INTPTR_MAX__ __INT64_MAX__\n"
|
||||
"#define __UINTPTR_MAX__ __UINT64_MAX__\n"
|
||||
"\n"
|
||||
"#define __FLT_MIN_EXP__ (-125)\n"
|
||||
"#define __FLT_MAX_EXP__ 128\n"
|
||||
"#define __FLT_DIG__ 6\n"
|
||||
"#define __FLT_DECIMAL_DIG__ 9\n"
|
||||
"#define __FLT_MANT_DIG__ 24\n"
|
||||
"#define __FLT_MIN__ 1.17549435082228750796873653722224568e-38F\n"
|
||||
"#define __FLT_MAX__ 3.40282346638528859811704183484516925e+38F\n"
|
||||
"#define __FLT_EPSILON__ 1.19209289550781250000000000000000000e-7F\n"
|
||||
"\n"
|
||||
"#define __DBL_MIN_EXP__ (-1021)\n"
|
||||
"#define __DBL_MAX_EXP__ 1024\n"
|
||||
"#define __DBL_DIG__ 15\n"
|
||||
"#define __DBL_DECIMAL_DIG__ 17\n"
|
||||
"#define __DBL_MANT_DIG__ 53\n"
|
||||
"#define __DBL_MAX__ ((double) 1.79769313486231570814527423731704357e+308L)\n"
|
||||
"#define __DBL_MIN__ ((double) 2.22507385850720138309023271733240406e-308L)\n"
|
||||
"#define __DBL_EPSILON__ ((double) 2.22044604925031308084726333618164062e-16L)\n"
|
||||
"\n"
|
||||
"typedef unsigned short char16_t;\n"
|
||||
"typedef unsigned int char32_t;\n"
|
||||
"\n"
|
||||
"#define __gnu_linux__ 1\n"
|
||||
"#define __linux 1\n"
|
||||
"#define __linux__ 1\n"
|
||||
"#define __unix 1\n"
|
||||
"#define __unix__ 1\n"
|
||||
"#define linux 1\n"
|
||||
"\n"
|
||||
"void *alloca (unsigned long);\n";
|
@ -0,0 +1,286 @@
|
||||
/* This file is a part of MIR project.
|
||||
Copyright (C) 2018, 2019 Vladimir Makarov <vmakarov.gcc@gmail.com>.
|
||||
*/
|
||||
|
||||
#ifndef MIR_BITMAP_H
|
||||
|
||||
#define MIR_BITMAP_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include "mir-varr.h"
|
||||
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
|
||||
#if !defined(BITMAP_ENABLE_CHECKING) && !defined(NDEBUG)
|
||||
#define BITMAP_ENABLE_CHECKING
|
||||
#endif
|
||||
|
||||
#ifndef BITMAP_ENABLE_CHECKING
|
||||
#define BITMAP_ASSERT(EXPR, OP) ((void) (EXPR))
|
||||
|
||||
#else
|
||||
static inline void mir_bitmap_assert_fail (const char *op) {
|
||||
fprintf (stderr, "wrong %s for a bitmap", op);
|
||||
assert (0);
|
||||
}
|
||||
|
||||
#define BITMAP_ASSERT(EXPR, OP) (void) ((EXPR) ? 0 : (mir_bitmap_assert_fail (#OP), 0))
|
||||
|
||||
#endif
|
||||
|
||||
#define BITMAP_WORD_BITS 64
|
||||
|
||||
typedef uint64_t bitmap_el_t;
|
||||
|
||||
DEF_VARR (bitmap_el_t);
|
||||
|
||||
typedef VARR (bitmap_el_t) * bitmap_t;
|
||||
typedef const VARR (bitmap_el_t) * const_bitmap_t;
|
||||
|
||||
static inline bitmap_t bitmap_create2 (size_t init_bits_num) {
|
||||
bitmap_t bm;
|
||||
|
||||
VARR_CREATE (bitmap_el_t, bm, (init_bits_num + BITMAP_WORD_BITS - 1) / BITMAP_WORD_BITS);
|
||||
return bm;
|
||||
}
|
||||
|
||||
static inline bitmap_t bitmap_create (void) { return bitmap_create2 (0); }
|
||||
|
||||
static inline void bitmap_destroy (bitmap_t bm) { VARR_DESTROY (bitmap_el_t, bm); }
|
||||
|
||||
static inline void bitmap_clear (bitmap_t bm) { VARR_TRUNC (bitmap_el_t, bm, 0); }
|
||||
|
||||
static inline void bitmap_expand (bitmap_t bm, size_t nb) {
|
||||
size_t i, len = VARR_LENGTH (bitmap_el_t, bm);
|
||||
size_t new_len = (nb + BITMAP_WORD_BITS - 1) / BITMAP_WORD_BITS;
|
||||
|
||||
for (i = len; i < new_len; i++) VARR_PUSH (bitmap_el_t, bm, (bitmap_el_t) 0);
|
||||
}
|
||||
|
||||
static inline int bitmap_bit_p (const_bitmap_t bm, size_t nb) {
|
||||
size_t nw, sh, len = VARR_LENGTH (bitmap_el_t, bm);
|
||||
bitmap_el_t *addr = VARR_ADDR (bitmap_el_t, bm);
|
||||
|
||||
if (nb >= BITMAP_WORD_BITS * len) return 0;
|
||||
nw = nb / BITMAP_WORD_BITS;
|
||||
sh = nb % BITMAP_WORD_BITS;
|
||||
return (addr[nw] >> sh) & 1;
|
||||
}
|
||||
|
||||
static inline int bitmap_set_bit_p (bitmap_t bm, size_t nb) {
|
||||
size_t nw, sh;
|
||||
bitmap_el_t *addr;
|
||||
int res;
|
||||
|
||||
bitmap_expand (bm, nb + 1);
|
||||
addr = VARR_ADDR (bitmap_el_t, bm);
|
||||
nw = nb / BITMAP_WORD_BITS;
|
||||
sh = nb % BITMAP_WORD_BITS;
|
||||
res = ((addr[nw] >> sh) & 1) == 0;
|
||||
addr[nw] |= (bitmap_el_t) 1 << sh;
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline int bitmap_clear_bit_p (bitmap_t bm, size_t nb) {
|
||||
size_t nw, sh, len = VARR_LENGTH (bitmap_el_t, bm);
|
||||
bitmap_el_t *addr = VARR_ADDR (bitmap_el_t, bm);
|
||||
int res;
|
||||
|
||||
if (nb >= BITMAP_WORD_BITS * len) return 0;
|
||||
nw = nb / BITMAP_WORD_BITS;
|
||||
sh = nb % BITMAP_WORD_BITS;
|
||||
res = (addr[nw] >> sh) & 1;
|
||||
addr[nw] &= ~((bitmap_el_t) 1 << sh);
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline void bitmap_copy (bitmap_t dst, const_bitmap_t src) {
|
||||
size_t dst_len = VARR_LENGTH (bitmap_el_t, dst);
|
||||
size_t src_len = VARR_LENGTH (bitmap_el_t, src);
|
||||
|
||||
if (dst_len >= src_len)
|
||||
VARR_TRUNC (bitmap_el_t, dst, src_len);
|
||||
else
|
||||
bitmap_expand (dst, src_len * BITMAP_WORD_BITS);
|
||||
memcpy (VARR_ADDR (bitmap_el_t, dst), VARR_ADDR (bitmap_el_t, src),
|
||||
src_len * sizeof (bitmap_el_t));
|
||||
}
|
||||
|
||||
static inline int bitmap_equal_p (const_bitmap_t bm1, const_bitmap_t bm2) {
|
||||
const_bitmap_t temp_bm;
|
||||
size_t i, temp_len, bm1_len = VARR_LENGTH (bitmap_el_t, bm1);
|
||||
size_t bm2_len = VARR_LENGTH (bitmap_el_t, bm2);
|
||||
bitmap_el_t *addr1, *addr2;
|
||||
|
||||
if (bm1_len > bm2_len) {
|
||||
temp_bm = bm1;
|
||||
bm1 = bm2;
|
||||
bm2 = temp_bm;
|
||||
temp_len = bm1_len;
|
||||
bm1_len = bm2_len;
|
||||
bm2_len = temp_len;
|
||||
}
|
||||
addr1 = VARR_ADDR (bitmap_el_t, bm1);
|
||||
addr2 = VARR_ADDR (bitmap_el_t, bm2);
|
||||
if (memcmp (addr1, addr2, bm1_len * sizeof (bitmap_el_t)) != 0) return FALSE;
|
||||
for (i = bm1_len; i < bm2_len; i++)
|
||||
if (addr2[i] != 0) return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline int bitmap_intersect_p (const_bitmap_t bm1, const_bitmap_t bm2) {
|
||||
size_t i, min_len, bm1_len = VARR_LENGTH (bitmap_el_t, bm1);
|
||||
size_t bm2_len = VARR_LENGTH (bitmap_el_t, bm2);
|
||||
bitmap_el_t *addr1 = VARR_ADDR (bitmap_el_t, bm1);
|
||||
bitmap_el_t *addr2 = VARR_ADDR (bitmap_el_t, bm2);
|
||||
|
||||
min_len = bm1_len <= bm2_len ? bm1_len : bm2_len;
|
||||
for (i = 0; i < min_len; i++)
|
||||
if ((addr1[i] & addr2[i]) != 0) return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static inline int bitmap_empty_p (const_bitmap_t bm) {
|
||||
size_t i, len = VARR_LENGTH (bitmap_el_t, bm);
|
||||
bitmap_el_t *addr = VARR_ADDR (bitmap_el_t, bm);
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
if (addr[i] != 0) return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline bitmap_el_t bitmap_el_max3 (bitmap_el_t el1, bitmap_el_t el2, bitmap_el_t el3) {
|
||||
if (el1 <= el2) return el2 < el3 ? el3 : el2;
|
||||
return el1 < el3 ? el3 : el1;
|
||||
}
|
||||
|
||||
static inline bitmap_el_t bitmap_el_max4 (bitmap_el_t el1, bitmap_el_t el2, bitmap_el_t el3,
|
||||
bitmap_el_t el4) {
|
||||
if (el1 <= el2) return bitmap_el_max3 (el2, el3, el4);
|
||||
return bitmap_el_max3 (el1, el3, el4);
|
||||
}
|
||||
|
||||
/* Return the number of bits set in BM. */
|
||||
static inline size_t bitmap_bit_count (const_bitmap_t bm) {
|
||||
size_t i, len = VARR_LENGTH (bitmap_el_t, bm);
|
||||
bitmap_el_t el, *addr = VARR_ADDR (bitmap_el_t, bm);
|
||||
size_t count = 0;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if ((el = addr[i]) != 0) {
|
||||
for (; el != 0; el >>= 1)
|
||||
if (el & 1) count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static inline int bitmap_op2 (bitmap_t dst, const_bitmap_t src1, const_bitmap_t src2,
|
||||
bitmap_el_t (*op) (bitmap_el_t, bitmap_el_t)) {
|
||||
size_t i, len, bound, src1_len, src2_len;
|
||||
bitmap_el_t old, *dst_addr, *src1_addr, *src2_addr;
|
||||
int change_p = FALSE;
|
||||
|
||||
src1_len = VARR_LENGTH (bitmap_el_t, src1);
|
||||
src2_len = VARR_LENGTH (bitmap_el_t, src2);
|
||||
len = bitmap_el_max3 (VARR_LENGTH (bitmap_el_t, dst), src1_len, src2_len);
|
||||
bitmap_expand (dst, len * BITMAP_WORD_BITS);
|
||||
dst_addr = VARR_ADDR (bitmap_el_t, dst);
|
||||
src1_addr = VARR_ADDR (bitmap_el_t, src1);
|
||||
src2_addr = VARR_ADDR (bitmap_el_t, src2);
|
||||
for (bound = i = 0; i < len; i++) {
|
||||
old = dst_addr[i];
|
||||
if ((dst_addr[i] = op (i >= src1_len ? 0 : src1_addr[i], i >= src2_len ? 0 : src2_addr[i]))
|
||||
!= 0)
|
||||
bound = i + 1;
|
||||
if (old != dst_addr[i]) change_p = TRUE;
|
||||
}
|
||||
VARR_TRUNC (bitmap_el_t, dst, bound);
|
||||
return change_p;
|
||||
}
|
||||
|
||||
static inline bitmap_el_t bitmap_el_and (bitmap_el_t el1, bitmap_el_t el2) { return el1 & el2; }
|
||||
|
||||
static inline int bitmap_and (bitmap_t dst, bitmap_t src1, bitmap_t src2) {
|
||||
return bitmap_op2 (dst, src1, src2, bitmap_el_and);
|
||||
}
|
||||
|
||||
static inline bitmap_el_t bitmap_el_and_compl (bitmap_el_t el1, bitmap_el_t el2) {
|
||||
return el1 & ~el2;
|
||||
}
|
||||
|
||||
static inline int bitmap_and_compl (bitmap_t dst, bitmap_t src1, bitmap_t src2) {
|
||||
return bitmap_op2 (dst, src1, src2, bitmap_el_and_compl);
|
||||
}
|
||||
|
||||
static inline bitmap_el_t bitmap_el_ior (bitmap_el_t el1, bitmap_el_t el2) { return el1 | el2; }
|
||||
|
||||
static inline int bitmap_ior (bitmap_t dst, bitmap_t src1, bitmap_t src2) {
|
||||
return bitmap_op2 (dst, src1, src2, bitmap_el_ior);
|
||||
}
|
||||
|
||||
static inline int bitmap_op3 (bitmap_t dst, const_bitmap_t src1, const_bitmap_t src2,
|
||||
const_bitmap_t src3,
|
||||
bitmap_el_t (*op) (bitmap_el_t, bitmap_el_t, bitmap_el_t)) {
|
||||
size_t i, len, bound, src1_len, src2_len, src3_len;
|
||||
bitmap_el_t old, *dst_addr, *src1_addr, *src2_addr, *src3_addr;
|
||||
int change_p = FALSE;
|
||||
|
||||
src1_len = VARR_LENGTH (bitmap_el_t, src1);
|
||||
src2_len = VARR_LENGTH (bitmap_el_t, src2);
|
||||
src3_len = VARR_LENGTH (bitmap_el_t, src3);
|
||||
len = bitmap_el_max4 (VARR_LENGTH (bitmap_el_t, dst), src1_len, src2_len, src3_len);
|
||||
bitmap_expand (dst, len * BITMAP_WORD_BITS);
|
||||
dst_addr = VARR_ADDR (bitmap_el_t, dst);
|
||||
src1_addr = VARR_ADDR (bitmap_el_t, src1);
|
||||
src2_addr = VARR_ADDR (bitmap_el_t, src2);
|
||||
src3_addr = VARR_ADDR (bitmap_el_t, src3);
|
||||
for (bound = i = 0; i < len; i++) {
|
||||
old = dst_addr[i];
|
||||
if ((dst_addr[i] = op (i >= src1_len ? 0 : src1_addr[i], i >= src2_len ? 0 : src2_addr[i],
|
||||
i >= src3_len ? 0 : src3_addr[i]))
|
||||
!= 0)
|
||||
bound = i + 1;
|
||||
if (old != dst_addr[i]) change_p = TRUE;
|
||||
}
|
||||
VARR_TRUNC (bitmap_el_t, dst, bound);
|
||||
return change_p;
|
||||
}
|
||||
|
||||
static inline bitmap_el_t bitmap_el_ior_and (bitmap_el_t el1, bitmap_el_t el2, bitmap_el_t el3) {
|
||||
return el1 | (el2 & el3);
|
||||
}
|
||||
|
||||
/* DST = SRC1 | (SRC2 & SRC3). Return true if DST changed. */
|
||||
static inline int bitmap_ior_and (bitmap_t dst, bitmap_t src1, bitmap_t src2, bitmap_t src3) {
|
||||
return bitmap_op3 (dst, src1, src2, src3, bitmap_el_ior_and);
|
||||
}
|
||||
|
||||
static inline bitmap_el_t bitmap_el_ior_and_compl (bitmap_el_t el1, bitmap_el_t el2,
|
||||
bitmap_el_t el3) {
|
||||
return el1 | (el2 & ~el3);
|
||||
}
|
||||
|
||||
/* DST = SRC1 | (SRC2 & ~SRC3). Return true if DST changed. */
|
||||
static inline int bitmap_ior_and_compl (bitmap_t dst, bitmap_t src1, bitmap_t src2, bitmap_t src3) {
|
||||
return bitmap_op3 (dst, src1, src2, src3, bitmap_el_ior_and_compl);
|
||||
}
|
||||
|
||||
static inline void bitmap_for_each (bitmap_t bm, void (*func) (size_t, void *), void *data) {
|
||||
size_t i, nb, len = VARR_LENGTH (bitmap_el_t, bm);
|
||||
bitmap_el_t el, *addr = VARR_ADDR (bitmap_el_t, bm);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if ((el = addr[i]) != 0) {
|
||||
for (nb = 0; el != 0; el >>= 1, nb++)
|
||||
if (el & 1) func (i * BITMAP_WORD_BITS + nb, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* #ifndef MIR_BITMAP_H */
|
@ -0,0 +1,175 @@
|
||||
/* This file is part of MIR project.
|
||||
Copyright (C) 2018, 2019 Vladimir Makarov <vmakarov.gcc@gmail.com>.
|
||||
*/
|
||||
|
||||
/* Typed doubly linked lists. */
|
||||
|
||||
#ifndef MIR_DLIST_H
|
||||
|
||||
#define MIR_DLIST_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#if !defined(DLIST_ENABLE_CHECKING) && !defined(NDEBUG)
|
||||
#define DLIST_ENABLE_CHECKING
|
||||
#endif
|
||||
|
||||
#ifndef DLIST_ENABLE_CHECKING
|
||||
#define DLIST_ASSERT(EXPR, OP, T) ((void) (EXPR))
|
||||
|
||||
#else
|
||||
static inline void dlist_assert_fail (const char* op, const char* var) {
|
||||
fprintf (stderr, "wrong %s for %s", op, var);
|
||||
assert (0);
|
||||
}
|
||||
|
||||
#define DLIST_ASSERT(EXPR, OP, T) (void) ((EXPR) ? 0 : (dlist_assert_fail (OP, #T), 0))
|
||||
|
||||
#endif
|
||||
|
||||
#define DLIST(T) DLIST_##T
|
||||
#define DLIST_OP(T, OP) DLIST_##T##_##OP
|
||||
#define DLIST_LINK(T) DLIST_LINK_##T
|
||||
|
||||
#define DLIST_LINK_T(T) \
|
||||
typedef struct DLIST_LINK (T) { \
|
||||
T prev, next; \
|
||||
} DLIST_LINK (T)
|
||||
|
||||
#define DEF_DLIST_LINK(T) DLIST_LINK_T (T);
|
||||
|
||||
#define DEF_DLIST_TYPE(T) \
|
||||
typedef struct DLIST (T) { \
|
||||
T head, tail; \
|
||||
} DLIST (T)
|
||||
|
||||
#define DEF_DLIST_CODE(T, LINK) \
|
||||
\
|
||||
static inline void DLIST_OP (T, init) (DLIST (T) * list) { list->head = list->tail = NULL; } \
|
||||
\
|
||||
static inline T DLIST_OP (T, head) (DLIST (T) * list) { return list->head; } \
|
||||
\
|
||||
static inline T DLIST_OP (T, tail) (DLIST (T) * list) { return list->tail; } \
|
||||
\
|
||||
static inline T DLIST_OP (T, prev) (T elem) { return elem->LINK.prev; } \
|
||||
static inline T DLIST_OP (T, next) (T elem) { return elem->LINK.next; } \
|
||||
\
|
||||
static inline T DLIST_OP (T, el) (DLIST (T) * list, int n) { \
|
||||
T e; \
|
||||
\
|
||||
if (n >= 0) { \
|
||||
for (e = list->head; e != NULL && n != 0; e = e->LINK.next, n--) \
|
||||
; \
|
||||
} else { \
|
||||
for (e = list->tail; e != NULL && n != -1; e = e->LINK.prev, n++) \
|
||||
; \
|
||||
} \
|
||||
return e; \
|
||||
} \
|
||||
\
|
||||
static inline void DLIST_OP (T, prepend) (DLIST (T) * list, T elem) { \
|
||||
DLIST_ASSERT (list&& elem, "prepend", T); \
|
||||
if (list->head == NULL) { \
|
||||
DLIST_ASSERT (list->tail == NULL, "prepend", T); \
|
||||
list->tail = elem; \
|
||||
} else { \
|
||||
DLIST_ASSERT (list->head->LINK.prev == NULL, "prepend", T); \
|
||||
list->head->LINK.prev = elem; \
|
||||
} \
|
||||
elem->LINK.prev = NULL; \
|
||||
elem->LINK.next = list->head; \
|
||||
list->head = elem; \
|
||||
} \
|
||||
\
|
||||
static inline void DLIST_OP (T, append) (DLIST (T) * list, T elem) { \
|
||||
DLIST_ASSERT (list&& elem, "append", T); \
|
||||
if (list->tail == NULL) { \
|
||||
DLIST_ASSERT (list->head == NULL, "append", T); \
|
||||
list->head = elem; \
|
||||
} else { \
|
||||
DLIST_ASSERT (list->tail->LINK.next == NULL, "append", T); \
|
||||
list->tail->LINK.next = elem; \
|
||||
} \
|
||||
elem->LINK.next = NULL; \
|
||||
elem->LINK.prev = list->tail; \
|
||||
list->tail = elem; \
|
||||
} \
|
||||
\
|
||||
static inline void DLIST_OP (T, insert_before) (DLIST (T) * list, T before, T elem) { \
|
||||
DLIST_ASSERT (list&& before&& elem && list->tail, "insert_before", T); \
|
||||
if (before->LINK.prev == NULL) { \
|
||||
DLIST_ASSERT (list->head == before, "insert_before", T); \
|
||||
before->LINK.prev = elem; \
|
||||
elem->LINK.next = before; \
|
||||
elem->LINK.prev = NULL; \
|
||||
list->head = elem; \
|
||||
} else { \
|
||||
DLIST_ASSERT (list->head, "insert_before", T); \
|
||||
before->LINK.prev->LINK.next = elem; \
|
||||
elem->LINK.prev = before->LINK.prev; \
|
||||
before->LINK.prev = elem; \
|
||||
elem->LINK.next = before; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline void DLIST_OP (T, insert_after) (DLIST (T) * list, T after, T elem) { \
|
||||
DLIST_ASSERT (list&& after&& elem && list->head, "insert_after", T); \
|
||||
if (after->LINK.next == NULL) { \
|
||||
DLIST_ASSERT (list->tail == after, "insert_after", T); \
|
||||
after->LINK.next = elem; \
|
||||
elem->LINK.prev = after; \
|
||||
elem->LINK.next = NULL; \
|
||||
list->tail = elem; \
|
||||
} else { \
|
||||
DLIST_ASSERT (list->tail, "insert_after", T); \
|
||||
after->LINK.next->LINK.prev = elem; \
|
||||
elem->LINK.next = after->LINK.next; \
|
||||
after->LINK.next = elem; \
|
||||
elem->LINK.prev = after; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline void DLIST_OP (T, remove) (DLIST (T) * list, T elem) { \
|
||||
DLIST_ASSERT (list&& elem, "remove", T); \
|
||||
if (elem->LINK.prev != NULL) { \
|
||||
elem->LINK.prev->LINK.next = elem->LINK.next; \
|
||||
} else { \
|
||||
DLIST_ASSERT (list->head == elem, "remove", T); \
|
||||
list->head = elem->LINK.next; \
|
||||
} \
|
||||
if (elem->LINK.next != NULL) { \
|
||||
elem->LINK.next->LINK.prev = elem->LINK.prev; \
|
||||
} else { \
|
||||
DLIST_ASSERT (list->tail == elem, "remove", T); \
|
||||
list->tail = elem->LINK.prev; \
|
||||
} \
|
||||
elem->LINK.prev = elem->LINK.next = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline size_t DLIST_OP (T, length) (DLIST (T) * list) { \
|
||||
size_t len = 0; \
|
||||
T curr; \
|
||||
\
|
||||
for (curr = list->head; curr != NULL; curr = curr->LINK.next) len++; \
|
||||
return len; \
|
||||
}
|
||||
|
||||
#define DEF_DLIST(T, LINK) \
|
||||
DEF_DLIST_TYPE (T); \
|
||||
DEF_DLIST_CODE (T, LINK)
|
||||
|
||||
#define DLIST_INIT(T, L) (DLIST_OP (T, init) (&(L)))
|
||||
#define DLIST_HEAD(T, L) (DLIST_OP (T, head) (&(L)))
|
||||
#define DLIST_TAIL(T, L) (DLIST_OP (T, tail) (&(L)))
|
||||
#define DLIST_PREV(T, E) (DLIST_OP (T, prev) (E))
|
||||
#define DLIST_NEXT(T, E) (DLIST_OP (T, next) (E))
|
||||
#define DLIST_EL(T, L, N) (DLIST_OP (T, el) (&(L), N))
|
||||
#define DLIST_PREPEND(T, L, E) (DLIST_OP (T, prepend) (&(L), (E)))
|
||||
#define DLIST_APPEND(T, L, E) (DLIST_OP (T, append) (&(L), (E)))
|
||||
#define DLIST_INSERT_BEFORE(T, L, B, E) (DLIST_OP (T, insert_before) (&(L), (B), (E)))
|
||||
#define DLIST_INSERT_AFTER(T, L, A, E) (DLIST_OP (T, insert_after) (&(L), (A), (E)))
|
||||
#define DLIST_REMOVE(T, L, E) (DLIST_OP (T, remove) (&(L), (E)))
|
||||
#define DLIST_LENGTH(T, L) (DLIST_OP (T, length) (&(L)))
|
||||
|
||||
#endif /* #ifndef MIR_DLIST_H */
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,22 @@
|
||||
/* This file is a part of MIR project.
|
||||
Copyright (C) 2018, 2019 Vladimir Makarov <vmakarov.gcc@gmail.com>.
|
||||
*/
|
||||
|
||||
#ifndef MIR_GEN_H
|
||||
|
||||
#define MIR_GEN_H
|
||||
|
||||
#include "mir.h"
|
||||
|
||||
#ifndef MIR_GEN_DEBUG
|
||||
#define MIR_GEN_DEBUG 0
|
||||
#endif
|
||||
|
||||
extern void MIR_gen_init (MIR_context_t context);
|
||||
extern void MIR_gen_set_debug_file (MIR_context_t context, FILE *f);
|
||||
extern void *MIR_gen (MIR_context_t context, MIR_item_t func_item);
|
||||
extern void MIR_set_gen_interface (MIR_context_t context, MIR_item_t func_item);
|
||||
extern void MIR_set_lazy_gen_interface (MIR_context_t context, MIR_item_t func_item);
|
||||
extern void MIR_gen_finish (MIR_context_t context);
|
||||
|
||||
#endif /* #ifndef MIR_GEN_H */
|
@ -0,0 +1,92 @@
|
||||
/* This file is a part of MIR project.
|
||||
|
||||
Copyright (C) 2018, 2019 Vladimir Makarov <vmakarov.gcc@gmail.com>.
|
||||
*/
|
||||
|
||||
/* Simple high-quality multiplicative hash passing demerphq-smhsher,
|
||||
faster than spooky, city, or xxhash for strings less 100 bytes.
|
||||
Hash for the same key can be different on different architectures.
|
||||
To get machine-independent hash, use mir_hash_strict which is about
|
||||
1.5 times slower than mir_hash. */
|
||||
#ifndef __MIR_HASH__
|
||||
#define __MIR_HASH__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__x86_64__) || defined(__i386__) || defined(__PPC64__) || defined(__s390__) \
|
||||
|| defined(__m32c__) || defined(cris) || defined(__CR16__) || defined(__vax__) \
|
||||
|| defined(__m68k__) || defined(__aarch64__) || defined(_M_AMD64) || defined(_M_IX86)
|
||||
#define MIR_HASH_UNALIGNED_ACCESS 1
|
||||
#else
|
||||
#define MIR_HASH_UNALIGNED_ACCESS 0
|
||||
#endif
|
||||
|
||||
static inline uint64_t mir_get_key_part (const uint8_t *v, size_t len, int relax_p) {
|
||||
size_t i, start = 0;
|
||||
uint64_t tail = 0;
|
||||
|
||||
if (relax_p || __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) {
|
||||
#if MIR_HASH_UNALIGNED_ACCESS
|
||||
if (len == sizeof (uint64_t)) return *(uint64_t *) v;
|
||||
if (len >= sizeof (uint32_t)) {
|
||||
tail = (uint64_t) * (uint32_t *) v << 32;
|
||||
start = 4;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
for (i = start; i < len; i++) tail = (tail >> 8) | ((uint64_t) v[i] << 56);
|
||||
return tail;
|
||||
}
|
||||
|
||||
static const uint64_t p1 = 0X65862b62bdf5ef4d, p2 = 0X288eea216831e6a7;
|
||||
static inline uint64_t mir_mum (uint64_t v, uint64_t c, int relax_p) {
|
||||
if (relax_p) {
|
||||
#if defined(__SIZEOF_INT128__)
|
||||
__uint128_t r = (__uint128_t) v * (__uint128_t) c;
|
||||
return (uint64_t) (r >> 64) + (uint64_t) r;
|
||||
#endif
|
||||
}
|
||||
uint64_t v1 = v >> 32, v2 = (uint32_t) v, c1 = c >> 32, c2 = (uint32_t) c, rm = v2 * c1 + v1 * c2;
|
||||
return v1 * c1 + (rm >> 32) + v2 * c2 + (rm << 32);
|
||||
}
|
||||
|
||||
static inline uint64_t mir_round (uint64_t state, uint64_t v, int relax_p) {
|
||||
state ^= mir_mum (v, p1, relax_p);
|
||||
return state ^ mir_mum (state, p2, relax_p);
|
||||
}
|
||||
|
||||
static inline uint64_t mir_hash_1 (const void *key, size_t len, uint64_t seed, int relax_p) {
|
||||
const uint8_t *v = (const uint8_t *) key;
|
||||
uint64_t r = seed + len;
|
||||
|
||||
for (; len >= 16; len -= 16, v += 16) {
|
||||
r ^= mir_mum (mir_get_key_part (v, 8, relax_p), p1, relax_p);
|
||||
r ^= mir_mum (mir_get_key_part (v + 8, 8, relax_p), p2, relax_p);
|
||||
r ^= mir_mum (r, p1, relax_p);
|
||||
}
|
||||
if (len >= 8) {
|
||||
r ^= mir_mum (mir_get_key_part (v, 8, relax_p), p1, relax_p);
|
||||
len -= 8, v += 8;
|
||||
}
|
||||
if (len != 0) r ^= mir_mum (mir_get_key_part (v, len, relax_p), p2, relax_p);
|
||||
return mir_round (r, r, relax_p);
|
||||
}
|
||||
|
||||
static inline uint64_t mir_hash (const void *key, size_t len, uint64_t seed) {
|
||||
return mir_hash_1 (key, len, seed, 1);
|
||||
}
|
||||
|
||||
static inline uint64_t mir_hash_strict (const void *key, size_t len, uint64_t seed) {
|
||||
return mir_hash_1 (key, len, seed, 0);
|
||||
}
|
||||
|
||||
static inline uint64_t mir_hash_init (uint64_t seed) { return seed; }
|
||||
static inline uint64_t mir_hash_step (uint64_t h, uint64_t key) { return mir_round (h, key, 1); }
|
||||
static inline uint64_t mir_hash_finish (uint64_t h) { return mir_round (h, h, 1); }
|
||||
|
||||
static inline uint64_t mir_hash64 (uint64_t key, uint64_t seed) {
|
||||
return mir_hash_finish (mir_hash_step (mir_hash_init (seed), key));
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,221 @@
|
||||
/* This file is a part of MIR project.
|
||||
Copyright (C) 2018, 2019 Vladimir Makarov <vmakarov.gcc@gmail.com>.
|
||||
*/
|
||||
|
||||
#ifndef MIR_HTAB_H
|
||||
#define MIR_HTAB_H
|
||||
|
||||
#include "mir-varr.h"
|
||||
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
|
||||
#if !defined(VARR_ENABLE_CHECKING) && !defined(NDEBUG)
|
||||
#define VARR_ENABLE_CHECKING
|
||||
#endif
|
||||
|
||||
#ifndef HTAB_ENABLE_CHECKING
|
||||
#define HTAB_ASSERT(EXPR, OP, T) ((void) (EXPR))
|
||||
|
||||
#else
|
||||
static inline void mir_htab_assert_fail (const char *op, const char *var) {
|
||||
fprintf (stderr, "wrong %s for %s\n", op, var);
|
||||
assert (0);
|
||||
}
|
||||
|
||||
#define HTAB_ASSERT(EXPR, OP, T) (void) ((EXPR) ? 0 : (mir_htab_assert_fail (OP, #T), 0))
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define MIR_HTAB_NO_RETURN __attribute__ ((noreturn))
|
||||
#else
|
||||
#define MIR_HTAB_NO_RETURN
|
||||
#endif
|
||||
|
||||
static inline void MIR_HTAB_NO_RETURN mir_htab_error (const char *message) {
|
||||
#ifdef MIR_HTAB_ERROR
|
||||
MIR_HTAB_ERROR (message);
|
||||
assert (FALSE);
|
||||
#else
|
||||
fprintf (stderr, "%s\n", message);
|
||||
#endif
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/*---------------- Typed hash table -----------------------------*/
|
||||
typedef unsigned htab_ind_t;
|
||||
typedef unsigned htab_size_t;
|
||||
typedef unsigned htab_hash_t;
|
||||
|
||||
#define HTAB_EMPTY_IND (~(htab_ind_t) 0)
|
||||
#define HTAB_DELETED_IND (HTAB_EMPTY_IND - 1)
|
||||
#define HTAB_DELETED_HASH 0
|
||||
|
||||
enum htab_action { HTAB_FIND, HTAB_INSERT, HTAB_REPLACE, HTAB_DELETE };
|
||||
|
||||
#define HTAB(T) HTAB_##T
|
||||
#define HTAB_OP(T, OP) HTAB_##T##_##OP
|
||||
|
||||
DEF_VARR (htab_ind_t)
|
||||
|
||||
#define HTAB_EL(T) HTAB_EL_##T
|
||||
|
||||
#define HTAB_T(T) \
|
||||
typedef struct HTAB_EL (T) { \
|
||||
htab_hash_t hash; \
|
||||
T el; \
|
||||
} HTAB_EL (T); \
|
||||
DEF_VARR (HTAB_EL (T)) \
|
||||
typedef struct { \
|
||||
htab_size_t els_num, els_start, els_bound, collisions; \
|
||||
htab_hash_t (*hash_func) (T el); \
|
||||
int (*eq_func) (T el1, T el2); \
|
||||
void (*free_func) (T el); \
|
||||
VARR (HTAB_EL (T)) * els; \
|
||||
VARR (htab_ind_t) * entries; \
|
||||
} HTAB (T);
|
||||
|
||||
#define DEF_HTAB(T) \
|
||||
HTAB_T (T) \
|
||||
\
|
||||
static inline void HTAB_OP (T, create) (HTAB (T) * *htab, htab_size_t min_size, \
|
||||
htab_hash_t (*hash_func) (T el), \
|
||||
int (*eq_func) (T el1, T el2), \
|
||||
void (*free_func) (T el)) { \
|
||||
HTAB (T) * ht; \
|
||||
htab_size_t i, size; \
|
||||
\
|
||||
for (size = 2; min_size > size; size *= 2) \
|
||||
; \
|
||||
ht = malloc (sizeof (*ht)); \
|
||||
if (ht == NULL) mir_htab_error ("htab: no memory"); \
|
||||
VARR_CREATE (HTAB_EL (T), ht->els, size); \
|
||||
VARR_TAILOR (HTAB_EL (T), ht->els, size); \
|
||||
VARR_CREATE (htab_ind_t, ht->entries, 2 * size); \
|
||||
ht->hash_func = hash_func; \
|
||||
ht->eq_func = eq_func; \
|
||||
ht->free_func = free_func; \
|
||||
ht->els_num = ht->els_start = ht->els_bound = ht->collisions = 0; \
|
||||
for (i = 0; i < 2 * size; i++) VARR_PUSH (htab_ind_t, ht->entries, HTAB_EMPTY_IND); \
|
||||
*htab = ht; \
|
||||
} \
|
||||
\
|
||||
static inline void HTAB_OP (T, clear) (HTAB (T) * htab) { \
|
||||
htab_ind_t *addr; \
|
||||
htab_size_t i, size; \
|
||||
HTAB_EL (T) * els_addr; \
|
||||
\
|
||||
HTAB_ASSERT (htab != NULL, "clear", T); \
|
||||
if (htab->free_func != NULL) { \
|
||||
els_addr = VARR_ADDR (HTAB_EL (T), htab->els); \
|
||||
size = VARR_LENGTH (HTAB_EL (T), htab->els); \
|
||||
for (i = 0; i < htab->els_bound; i++) \
|
||||
if (els_addr[i].hash != HTAB_DELETED_HASH) htab->free_func (els_addr[i].el); \
|
||||
} \
|
||||
htab->els_num = htab->els_start = htab->els_bound = 0; \
|
||||
addr = VARR_ADDR (htab_ind_t, htab->entries); \
|
||||
size = VARR_LENGTH (htab_ind_t, htab->entries); \
|
||||
for (i = 0; i < size; i++) addr[i] = HTAB_EMPTY_IND; \
|
||||
} \
|
||||
\
|
||||
static inline void HTAB_OP (T, destroy) (HTAB (T) * *htab) { \
|
||||
HTAB_ASSERT (*htab != NULL, "destroy", T); \
|
||||
if ((*htab)->free_func != NULL) HTAB_OP (T, clear) (*htab); \
|
||||
VARR_DESTROY (HTAB_EL (T), (*htab)->els); \
|
||||
VARR_DESTROY (htab_ind_t, (*htab)->entries); \
|
||||
free (*htab); \
|
||||
*htab = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline int HTAB_OP (T, do) (HTAB (T) * htab, T el, enum htab_action action, T * res) { \
|
||||
htab_ind_t ind, el_ind, *entry, *first_deleted_entry = NULL; \
|
||||
htab_hash_t hash, peterb; \
|
||||
htab_size_t els_size, size, mask, start, bound, i; \
|
||||
htab_ind_t *addr; \
|
||||
HTAB_EL (T) * els_addr; \
|
||||
\
|
||||
HTAB_ASSERT (htab != NULL, "do htab", T); \
|
||||
size = VARR_LENGTH (htab_ind_t, htab->entries); \
|
||||
els_size = VARR_LENGTH (HTAB_EL (T), htab->els); \
|
||||
HTAB_ASSERT (els_size * 2 == size, "do size", T); \
|
||||
if ((action == HTAB_INSERT || action == HTAB_REPLACE) && htab->els_bound == els_size) { \
|
||||
size *= 2; \
|
||||
VARR_TAILOR (htab_ind_t, htab->entries, size); \
|
||||
addr = VARR_ADDR (htab_ind_t, htab->entries); \
|
||||
for (i = 0; i < size; i++) addr[i] = HTAB_EMPTY_IND; \
|
||||
VARR_TAILOR (HTAB_EL (T), htab->els, els_size * 2); \
|
||||
els_addr = VARR_ADDR (HTAB_EL (T), htab->els); \
|
||||
start = htab->els_start; \
|
||||
bound = htab->els_bound; \
|
||||
htab->els_start = htab->els_bound = htab->els_num = 0; \
|
||||
for (i = start; i < bound; i++) \
|
||||
if (els_addr[i].hash != HTAB_DELETED_HASH) { \
|
||||
HTAB_OP (T, do) (htab, els_addr[i].el, HTAB_INSERT, res); \
|
||||
HTAB_ASSERT ((*htab->eq_func) (*res, els_addr[i].el), "do expand", T); \
|
||||
} \
|
||||
HTAB_ASSERT (bound - start >= htab->els_bound, "do bound", T); \
|
||||
} \
|
||||
mask = size - 1; \
|
||||
hash = (*htab->hash_func) (el); \
|
||||
if (hash == HTAB_DELETED_HASH) hash += 1; \
|
||||
peterb = hash; \
|
||||
ind = hash & mask; \
|
||||
addr = VARR_ADDR (htab_ind_t, htab->entries); \
|
||||
els_addr = VARR_ADDR (HTAB_EL (T), htab->els); \
|
||||
for (;; htab->collisions++) { \
|
||||
entry = addr + ind; \
|
||||
el_ind = *entry; \
|
||||
if (el_ind != HTAB_EMPTY_IND) { \
|
||||
if (el_ind == HTAB_DELETED_IND) { \
|
||||
first_deleted_entry = entry; \
|
||||
} else if (els_addr[el_ind].hash == hash && (*htab->eq_func) (els_addr[el_ind].el, el)) { \
|
||||
if (action == HTAB_REPLACE) { \
|
||||
if (htab->free_func != NULL) htab->free_func (els_addr[el_ind].el); \
|
||||
els_addr[el_ind].el = el; \
|
||||
} \
|
||||
if (action != HTAB_DELETE) { \
|
||||
*res = els_addr[el_ind].el; \
|
||||
} else { \
|
||||
htab->els_num--; \
|
||||
*entry = HTAB_DELETED_IND; \
|
||||
if (htab->free_func != NULL) htab->free_func (els_addr[el_ind].el); \
|
||||
els_addr[el_ind].hash = HTAB_DELETED_HASH; \
|
||||
} \
|
||||
return TRUE; \
|
||||
} \
|
||||
} else { \
|
||||
if (action == HTAB_INSERT || action == HTAB_REPLACE) { \
|
||||
htab->els_num++; \
|
||||
if (first_deleted_entry != NULL) entry = first_deleted_entry; \
|
||||
els_addr[htab->els_bound].hash = hash; \
|
||||
els_addr[htab->els_bound].el = el; \
|
||||
*entry = htab->els_bound++; \
|
||||
*res = el; \
|
||||
} \
|
||||
return FALSE; \
|
||||
} \
|
||||
peterb >>= 11; \
|
||||
ind = (5 * ind + peterb + 1) & mask; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline htab_size_t HTAB_OP (T, els_num) (HTAB (T) * htab) { \
|
||||
HTAB_ASSERT (htab != NULL, "els_num", T); \
|
||||
return htab->els_num; \
|
||||
} \
|
||||
static inline htab_size_t HTAB_OP (T, collisions) (HTAB (T) * htab) { \
|
||||
HTAB_ASSERT (htab != NULL, "collisions", T); \
|
||||
return htab->collisions; \
|
||||
}
|
||||
|
||||
#define HTAB_CREATE(T, V, S, H, EQ) (HTAB_OP (T, create) (&(V), S, H, EQ, NULL))
|
||||
#define HTAB_CREATE_WITH_FREE_FUNC(T, V, S, H, EQ, F) (HTAB_OP (T, create) (&(V), S, H, EQ, F))
|
||||
#define HTAB_CLEAR(T, V) (HTAB_OP (T, clear) (V))
|
||||
#define HTAB_DESTROY(T, V) (HTAB_OP (T, destroy) (&(V)))
|
||||
/* It returns TRUE if the element existed in the table. */
|
||||
#define HTAB_DO(T, V, EL, A, TAB_EL) (HTAB_OP (T, do) (V, EL, A, &(TAB_EL)))
|
||||
#define HTAB_ELS_NUM(T, V) (HTAB_OP (T, els_num) (V))
|
||||
#define HTAB_COLLISIONS(T, V) (HTAB_OP (T, collisions) (V))
|
||||
|
||||
#endif /* #ifndef MIR_HTAB_H */
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,463 @@
|
||||
/* This file is a part of MIR project.
|
||||
Copyright (C) 2018, 2019 Vladimir Makarov <vmakarov.gcc@gmail.com>.
|
||||
*/
|
||||
|
||||
#ifndef MIR_REDUCE_H
|
||||
#define MIR_REDUCE_H
|
||||
|
||||
/* Data compression. Major goals are simplicity, fast decompression
|
||||
speed, moderate compression speed. The algorithm is tuned for
|
||||
binary MIR compression and close to LZ4. Only we use a bit
|
||||
different format and offsets in symbol numbers instead of just
|
||||
offsets.
|
||||
|
||||
A better compression (on par with LZ4) could be achieved by adding
|
||||
elements for all positions (now positions inside referenced symbols
|
||||
are excluded) or/and increasing the buffer or/and increasing the
|
||||
table. But it would slow down the compression or/and increase the
|
||||
used memory.
|
||||
|
||||
Functions reduce_encode, reduce_decode, reduce_encode_start,
|
||||
reduce_encode_put, reduce_encode_finish, reduce_decode_start,
|
||||
reduce_decode_get, reduce_decode_finish are the only interface
|
||||
functions.
|
||||
|
||||
Format of compressed data: "MIR", elements*, zero byte, 8-byte check hash in little endian form
|
||||
Format of element:
|
||||
o 8 bits tag
|
||||
(N bits for symbol length; 0 means no sym, 2^N -1 means symbol length as uint present;
|
||||
(8-N) bits for reference length; 0 means no ref, 2^(8-N) - 1 means length as uint present)
|
||||
o [uint for symbol lenght]*, symbol string,
|
||||
o [uint for ref len]*, symbol number as uint */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "mir-hash.h"
|
||||
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
#define _REDUCE_DATA_PREFIX "MIR" /* first chars of compressed data */
|
||||
#define _REDUCE_SYMB_TAG_LEN 3 /* for some application could be 4 */
|
||||
#define _REDUCE_SYMB_TAG_LONG ((1 << _REDUCE_SYMB_TAG_LEN) - 1) /* should be not changed */
|
||||
#define _REDUCE_REF_TAG_LEN (8 - _REDUCE_SYMB_TAG_LEN)
|
||||
#define _REDUCE_REF_TAG_LONG ((1 << _REDUCE_REF_TAG_LEN) - 1) /* should be not changed */
|
||||
#define _REDUCE_START_LEN 4 /* Should be at least 4 */
|
||||
#define _REDUCE_BUF_LEN (1 << 18)
|
||||
/* The following should be power of two. There will be no space saving if it is less than 1/4 of buf
|
||||
length. */
|
||||
#define _REDUCE_TABLE_SIZE (_REDUCE_BUF_LEN / 4)
|
||||
#define _REDUCE_MAX_SYMB_LEN (2047)
|
||||
|
||||
typedef size_t (*reduce_reader_t) (void *start, size_t len, void *aux_data);
|
||||
typedef size_t (*reduce_writer_t) (const void *start, size_t len, void *aux_data);
|
||||
|
||||
struct _reduce_el {
|
||||
uint32_t pos, num, next, head;
|
||||
};
|
||||
|
||||
struct _reduce_encode_data {
|
||||
reduce_writer_t writer;
|
||||
uint32_t el_free;
|
||||
uint32_t curr_symb_len;
|
||||
uint8_t curr_symb[_REDUCE_MAX_SYMB_LEN];
|
||||
struct _reduce_el table[_REDUCE_TABLE_SIZE]; /* hash -> el */
|
||||
};
|
||||
|
||||
struct _reduce_decode_data {
|
||||
uint8_t eof_p;
|
||||
uint32_t buf_get_pos;
|
||||
reduce_reader_t reader;
|
||||
uint32_t ind2pos[_REDUCE_BUF_LEN];
|
||||
};
|
||||
|
||||
struct reduce_data {
|
||||
union {
|
||||
struct _reduce_encode_data encode;
|
||||
struct _reduce_decode_data decode;
|
||||
} u;
|
||||
void *aux_data;
|
||||
uint8_t ok_p;
|
||||
uint64_t check_hash;
|
||||
uint32_t curr_num, buf_bound;
|
||||
uint8_t buf[_REDUCE_BUF_LEN];
|
||||
};
|
||||
|
||||
static inline uint32_t _reduce_min (uint32_t a, uint32_t b) { return a < b ? a : b; }
|
||||
|
||||
static inline uint32_t _reduce_get_new_el (struct reduce_data *data) {
|
||||
struct _reduce_encode_data *encode_data = &data->u.encode;
|
||||
uint32_t res = encode_data->el_free;
|
||||
|
||||
if (res != UINT32_MAX) encode_data->el_free = encode_data->table[res].next;
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline void _reduce_put (struct reduce_data *data, int byte) {
|
||||
uint8_t u = byte;
|
||||
|
||||
if (data->u.encode.writer (&u, 1, data->aux_data) != 1) data->ok_p = FALSE;
|
||||
}
|
||||
|
||||
static inline int _reduce_get (reduce_reader_t reader, void *aux_data) {
|
||||
uint8_t u;
|
||||
|
||||
if (reader (&u, 1, aux_data) != 1) return -1;
|
||||
return u;
|
||||
}
|
||||
|
||||
static inline uint32_t _reduce_ref_offset_size (uint32_t offset) {
|
||||
return offset < (1 << 7) ? 1 : offset < (1 << 14) ? 2 : offset < (1 << 21) ? 3 : 4;
|
||||
}
|
||||
|
||||
static inline uint32_t _reduce_ref_size (uint32_t len, uint32_t offset) {
|
||||
assert (len >= _REDUCE_START_LEN);
|
||||
len -= _REDUCE_START_LEN - 1;
|
||||
return ((len < _REDUCE_REF_TAG_LONG ? 0 : _reduce_ref_offset_size (len))
|
||||
+ _reduce_ref_offset_size (offset));
|
||||
}
|
||||
|
||||
static inline void _reduce_uint_write (struct reduce_data *data, uint32_t u) {
|
||||
int n;
|
||||
|
||||
assert (u < (1 << 7 * 4));
|
||||
for (n = 1; n <= 4 && u >= (1 << 7 * n); n++)
|
||||
;
|
||||
_reduce_put (data, (1 << (8 - n)) | (u >> (n - 1) * 8) & 0xff); /* tag */
|
||||
for (int i = 2; i <= n; i++) _reduce_put (data, (u >> (n - i) * 8) & 0xff);
|
||||
}
|
||||
|
||||
static inline int64_t _reduce_uint_read (reduce_reader_t reader, void *aux_data) {
|
||||
int i, n, r = _reduce_get (reader, aux_data);
|
||||
uint32_t u, v;
|
||||
|
||||
if (r < 0) return -1;
|
||||
for (u = (uint32_t) r, n = 1; n <= 4 && (u >> (8 - n)) != 1; n++)
|
||||
;
|
||||
assert ((u >> (8 - n)) == 1);
|
||||
v = u & (0xff >> n);
|
||||
for (i = 1; i < n; i++) {
|
||||
if ((r = _reduce_get (reader, aux_data)) < 0) return -1;
|
||||
v = v * 256 + (uint32_t) r;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline void _reduce_hash_write (struct reduce_data *data, uint64_t h) {
|
||||
_reduce_put (data, 0); /* 0 tag */
|
||||
for (int i = 0; i < sizeof (uint64_t); i++) _reduce_put (data, (h >> i * 8) & 0xff);
|
||||
}
|
||||
|
||||
static inline uint64_t _reduce_str2hash (const uint8_t *s) {
|
||||
uint64_t h = 0;
|
||||
|
||||
for (int i = 0; i < sizeof (uint64_t); i++) h |= (uint64_t) s[i] << i * 8;
|
||||
return h;
|
||||
}
|
||||
|
||||
static inline int _reduce_symb_flush (struct reduce_data *data, int ref_tag) {
|
||||
uint8_t u;
|
||||
struct _reduce_encode_data *encode_data = &data->u.encode;
|
||||
uint32_t len = encode_data->curr_symb_len;
|
||||
|
||||
if (len == 0 && ref_tag == 0) return FALSE;
|
||||
u = ((len < _REDUCE_SYMB_TAG_LONG ? len : _REDUCE_SYMB_TAG_LONG) << _REDUCE_REF_TAG_LEN)
|
||||
| ref_tag;
|
||||
encode_data->writer (&u, 1, data->aux_data);
|
||||
if (len >= _REDUCE_SYMB_TAG_LONG) _reduce_uint_write (data, len);
|
||||
encode_data->writer (encode_data->curr_symb, len, data->aux_data);
|
||||
encode_data->curr_symb_len = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline void _reduce_output_byte (struct reduce_data *data, uint32_t pos) {
|
||||
struct _reduce_encode_data *encode_data = &data->u.encode;
|
||||
|
||||
if (encode_data->curr_symb_len + 1 > _REDUCE_MAX_SYMB_LEN) {
|
||||
_reduce_symb_flush (data, 0);
|
||||
encode_data->curr_symb_len = 0;
|
||||
}
|
||||
encode_data->curr_symb[encode_data->curr_symb_len++] = data->buf[pos];
|
||||
}
|
||||
|
||||
static inline void _reduce_output_ref (struct reduce_data *data, uint32_t offset, uint32_t len) {
|
||||
uint32_t ref_tag;
|
||||
|
||||
assert (len >= _REDUCE_START_LEN);
|
||||
len -= _REDUCE_START_LEN - 1;
|
||||
ref_tag = len < _REDUCE_REF_TAG_LONG ? len : _REDUCE_REF_TAG_LONG;
|
||||
_reduce_symb_flush (data, ref_tag);
|
||||
if (len >= _REDUCE_REF_TAG_LONG) _reduce_uint_write (data, len);
|
||||
_reduce_uint_write (data, offset);
|
||||
}
|
||||
|
||||
#define _REDUCE_HASH_SEED 24
|
||||
|
||||
static inline uint32_t _reduce_dict_find_longest (struct reduce_data *data, uint32_t pos,
|
||||
uint32_t *dict_pos) {
|
||||
uint32_t len, best_len, len_bound;
|
||||
uint64_t hash;
|
||||
uint32_t off, best_off, ref_size, best_ref_size;
|
||||
uint32_t curr, prev, next;
|
||||
const uint8_t *s1, *s2;
|
||||
struct _reduce_el *el, *best_el = NULL;
|
||||
struct _reduce_encode_data *encode_data = &data->u.encode;
|
||||
|
||||
if (pos + _REDUCE_START_LEN > data->buf_bound) return 0;
|
||||
/* To have the same compressed output independently of the target
|
||||
and the used compiler, use strict hash even if it decreases
|
||||
compression speed by 10%. */
|
||||
hash
|
||||
= mir_hash_strict (&data->buf[pos], _REDUCE_START_LEN, _REDUCE_HASH_SEED) % _REDUCE_TABLE_SIZE;
|
||||
for (curr = encode_data->table[hash].head, prev = UINT32_MAX; curr != UINT32_MAX;
|
||||
prev = curr, curr = next) {
|
||||
next = encode_data->table[curr].next;
|
||||
el = &encode_data->table[curr];
|
||||
len_bound = _reduce_min (data->buf_bound - pos, pos - el->pos);
|
||||
if (len_bound < _REDUCE_START_LEN) continue;
|
||||
s1 = &data->buf[el->pos];
|
||||
s2 = &data->buf[pos];
|
||||
#if MIR_HASH_UNALIGNED_ACCESS
|
||||
assert (_REDUCE_START_LEN >= 4);
|
||||
if (*(uint32_t *) &s1[0] != *(uint32_t *) &s2[0]) continue;
|
||||
len = 4;
|
||||
#else
|
||||
len = 0;
|
||||
#endif
|
||||
for (; len < len_bound; len++)
|
||||
if (s1[len] != s2[len]) break;
|
||||
#if !MIR_HASH_UNALIGNED_ACCESS
|
||||
if (len < _REDUCE_START_LEN) continue;
|
||||
#endif
|
||||
off = data->curr_num - el->num;
|
||||
if (best_el == NULL) {
|
||||
best_len = len;
|
||||
best_el = el;
|
||||
best_ref_size = _reduce_ref_size (len, off);
|
||||
continue;
|
||||
}
|
||||
best_off = data->curr_num - best_el->num;
|
||||
ref_size = _reduce_ref_size (len, off);
|
||||
if (best_len + ref_size < len + best_ref_size) {
|
||||
best_len = len;
|
||||
best_el = el;
|
||||
best_ref_size = ref_size;
|
||||
}
|
||||
}
|
||||
if (best_el == NULL) return 0;
|
||||
*dict_pos = best_el->num;
|
||||
return best_len;
|
||||
}
|
||||
|
||||
static inline void _reduce_dict_add (struct reduce_data *data, uint32_t pos) {
|
||||
uint64_t hash;
|
||||
struct _reduce_el *el;
|
||||
uint32_t prev, curr, num = data->curr_num++;
|
||||
struct _reduce_encode_data *encode_data = &data->u.encode;
|
||||
|
||||
if (pos + _REDUCE_START_LEN > data->buf_bound) return;
|
||||
hash
|
||||
= mir_hash_strict (&data->buf[pos], _REDUCE_START_LEN, _REDUCE_HASH_SEED) % _REDUCE_TABLE_SIZE;
|
||||
if ((curr = _reduce_get_new_el (data)) == UINT32_MAX) { /* rare case: use last if any */
|
||||
for (prev = UINT32_MAX, curr = encode_data->table[hash].head;
|
||||
curr != UINT32_MAX && encode_data->table[curr].next != UINT32_MAX;
|
||||
prev = curr, curr = encode_data->table[curr].next)
|
||||
;
|
||||
if (curr == UINT32_MAX) return; /* no more free els */
|
||||
if (prev != UINT32_MAX)
|
||||
encode_data->table[prev].next = encode_data->table[curr].next;
|
||||
else
|
||||
encode_data->table[hash].head = encode_data->table[curr].next;
|
||||
}
|
||||
encode_data->table[curr].pos = pos;
|
||||
encode_data->table[curr].num = num;
|
||||
encode_data->table[curr].next = encode_data->table[hash].head;
|
||||
encode_data->table[hash].head = curr;
|
||||
}
|
||||
|
||||
static void _reduce_reset_next (struct reduce_data *data) {
|
||||
struct _reduce_encode_data *encode_data = &data->u.encode;
|
||||
|
||||
for (uint32_t i = 0; i < _REDUCE_TABLE_SIZE; i++) {
|
||||
encode_data->table[i].next = i + 1;
|
||||
encode_data->table[i].head = UINT32_MAX;
|
||||
}
|
||||
encode_data->table[_REDUCE_TABLE_SIZE - 1].next = UINT32_MAX;
|
||||
encode_data->el_free = 0;
|
||||
}
|
||||
|
||||
#define _REDUCE_CHECK_HASH_SEED 42
|
||||
|
||||
static inline struct reduce_data *reduce_encode_start (reduce_writer_t writer, void *aux_data) {
|
||||
struct reduce_data *data = malloc (sizeof (struct reduce_data));
|
||||
char prefix[] = _REDUCE_DATA_PREFIX;
|
||||
size_t prefix_size = strlen (prefix);
|
||||
|
||||
if (data == NULL) return data;
|
||||
data->u.encode.writer = writer;
|
||||
data->aux_data = aux_data;
|
||||
data->check_hash = _REDUCE_CHECK_HASH_SEED;
|
||||
data->buf_bound = 0;
|
||||
data->ok_p = writer (prefix, prefix_size, aux_data) == prefix_size;
|
||||
return data;
|
||||
}
|
||||
|
||||
static inline void _reduce_encode_buf (struct reduce_data *data) {
|
||||
uint32_t dict_len, dict_pos, base;
|
||||
|
||||
if (data->buf_bound == 0) return;
|
||||
data->check_hash = mir_hash_strict (data->buf, data->buf_bound, data->check_hash);
|
||||
data->curr_num = data->u.encode.curr_symb_len = 0;
|
||||
_reduce_reset_next (data);
|
||||
for (uint32_t pos = 0; pos < data->buf_bound;) {
|
||||
dict_len = _reduce_dict_find_longest (data, pos, &dict_pos);
|
||||
base = data->curr_num;
|
||||
if (dict_len == 0) {
|
||||
_reduce_output_byte (data, pos);
|
||||
_reduce_dict_add (data, pos);
|
||||
pos++;
|
||||
continue;
|
||||
}
|
||||
_reduce_output_ref (data, base - dict_pos, dict_len);
|
||||
_reduce_dict_add (data, pos); /* replace */
|
||||
pos += dict_len;
|
||||
}
|
||||
_reduce_symb_flush (data, 0);
|
||||
}
|
||||
|
||||
static inline void reduce_encode_put (struct reduce_data *data, int c) {
|
||||
if (data->buf_bound < _REDUCE_BUF_LEN) {
|
||||
data->buf[data->buf_bound++] = c;
|
||||
return;
|
||||
}
|
||||
_reduce_encode_buf (data);
|
||||
data->buf_bound = 0;
|
||||
data->buf[data->buf_bound++] = c;
|
||||
}
|
||||
|
||||
static inline int reduce_encode_finish (struct reduce_data *data) {
|
||||
int ok_p;
|
||||
|
||||
_reduce_encode_buf (data);
|
||||
_reduce_hash_write (data, data->check_hash);
|
||||
ok_p = data->ok_p;
|
||||
free (data);
|
||||
return ok_p;
|
||||
}
|
||||
|
||||
static inline struct reduce_data *reduce_decode_start (reduce_reader_t reader, void *aux_data) {
|
||||
struct reduce_data *data = malloc (sizeof (struct reduce_data));
|
||||
struct _reduce_decode_data *decode_data = &data->u.decode;
|
||||
char prefix[] = _REDUCE_DATA_PREFIX, str[sizeof (prefix)];
|
||||
size_t prefix_size = strlen (prefix);
|
||||
|
||||
if (data == NULL) return data;
|
||||
decode_data->reader = reader;
|
||||
data->aux_data = aux_data;
|
||||
data->check_hash = _REDUCE_CHECK_HASH_SEED;
|
||||
decode_data->buf_get_pos = data->buf_bound = 0;
|
||||
data->ok_p
|
||||
= reader (str, prefix_size, aux_data) == prefix_size && memcmp (prefix, str, prefix_size) == 0;
|
||||
decode_data->eof_p = FALSE;
|
||||
return data;
|
||||
}
|
||||
|
||||
static inline int reduce_decode_get (struct reduce_data *data) {
|
||||
uint8_t tag, hash_str[sizeof (uint64_t)];
|
||||
uint32_t sym_len, ref_len, ref_ind, sym_pos, pos = 0, curr_ind = 0;
|
||||
uint64_t r;
|
||||
struct _reduce_decode_data *decode_data = &data->u.decode;
|
||||
reduce_reader_t reader = decode_data->reader;
|
||||
|
||||
if (decode_data->buf_get_pos < data->buf_bound) return data->buf[decode_data->buf_get_pos++];
|
||||
if (decode_data->eof_p) return -1;
|
||||
for (;;) {
|
||||
if (reader (&tag, 1, data->aux_data) == 0) break;
|
||||
if (tag == 0) { /* check hash */
|
||||
if (reader (hash_str, sizeof (hash_str), data->aux_data) != sizeof (hash_str)
|
||||
|| reader (&tag, 1, data->aux_data) != 0)
|
||||
break;
|
||||
if (pos != 0) data->check_hash = mir_hash_strict (data->buf, pos, data->check_hash);
|
||||
if (_reduce_str2hash (hash_str) != data->check_hash) break;
|
||||
decode_data->eof_p = TRUE;
|
||||
decode_data->buf_get_pos = 0;
|
||||
data->buf_bound = pos;
|
||||
return pos == 0 ? -1 : data->buf[decode_data->buf_get_pos++];
|
||||
}
|
||||
sym_len = tag >> _REDUCE_REF_TAG_LEN;
|
||||
if (sym_len != 0) {
|
||||
if (sym_len == _REDUCE_SYMB_TAG_LONG) {
|
||||
if ((r = _reduce_uint_read (reader, data->aux_data)) < 0) break;
|
||||
sym_len = r;
|
||||
}
|
||||
if (sym_len > _REDUCE_MAX_SYMB_LEN || pos + sym_len > _REDUCE_BUF_LEN) break;
|
||||
if (reader (&data->buf[pos], sym_len, data->aux_data) != sym_len) break;
|
||||
for (uint32_t i = 0; i < sym_len; i++, pos++, curr_ind++)
|
||||
decode_data->ind2pos[curr_ind] = pos;
|
||||
}
|
||||
ref_len = tag & _REDUCE_REF_TAG_LONG;
|
||||
if (ref_len != 0) {
|
||||
if (ref_len == _REDUCE_REF_TAG_LONG) {
|
||||
if ((r = _reduce_uint_read (reader, data->aux_data)) < 0) break;
|
||||
ref_len = r;
|
||||
}
|
||||
ref_len += _REDUCE_START_LEN - 1;
|
||||
if ((r = _reduce_uint_read (reader, data->aux_data)) < 0) break;
|
||||
ref_ind = r;
|
||||
if (curr_ind < ref_ind) break;
|
||||
sym_pos = decode_data->ind2pos[curr_ind - ref_ind];
|
||||
if (sym_pos + ref_len > _REDUCE_BUF_LEN) break;
|
||||
memcpy (&data->buf[pos], &data->buf[sym_pos], ref_len);
|
||||
decode_data->ind2pos[curr_ind++] = pos;
|
||||
pos += ref_len;
|
||||
}
|
||||
if (pos >= _REDUCE_BUF_LEN) {
|
||||
assert (pos == _REDUCE_BUF_LEN);
|
||||
data->check_hash = mir_hash_strict (data->buf, pos, data->check_hash);
|
||||
data->buf_bound = _REDUCE_BUF_LEN;
|
||||
decode_data->buf_get_pos = 0;
|
||||
return data->buf[decode_data->buf_get_pos++];
|
||||
}
|
||||
}
|
||||
data->ok_p = FALSE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int reduce_decode_finish (struct reduce_data *data) {
|
||||
uint8_t tag;
|
||||
int ok_p
|
||||
= data->ok_p && data->u.decode.eof_p && data->u.decode.reader (&tag, 1, data->aux_data) == 0;
|
||||
|
||||
free (data);
|
||||
return ok_p;
|
||||
}
|
||||
|
||||
#define _REDUCE_WRITE_IO_LEN 256
|
||||
static inline int reduce_encode (reduce_reader_t reader, reduce_writer_t writer, void *aux_data) {
|
||||
size_t i, size;
|
||||
uint8_t buf[_REDUCE_WRITE_IO_LEN];
|
||||
struct reduce_data *data = reduce_encode_start (writer, aux_data);
|
||||
|
||||
if (data == NULL) return FALSE;
|
||||
for (;;) {
|
||||
if ((size = reader (buf, _REDUCE_WRITE_IO_LEN, data->aux_data)) == 0) break;
|
||||
for (i = 0; i < size; i++) reduce_encode_put (data, buf[i]);
|
||||
}
|
||||
return reduce_encode_finish (data);
|
||||
}
|
||||
|
||||
static inline int reduce_decode (reduce_reader_t reader, reduce_writer_t writer, void *aux_data) {
|
||||
int c, i;
|
||||
uint8_t buf[_REDUCE_WRITE_IO_LEN];
|
||||
struct reduce_data *data = reduce_decode_start (reader, aux_data);
|
||||
|
||||
if (data == NULL) return FALSE;
|
||||
for (;;) {
|
||||
for (i = 0; i < _REDUCE_WRITE_IO_LEN && (c = reduce_decode_get (data)) >= 0; i++) buf[i] = c;
|
||||
if (i != 0) writer (buf, i, aux_data);
|
||||
if (c < 0) break;
|
||||
}
|
||||
return reduce_decode_finish (data);
|
||||
}
|
||||
|
||||
#endif /* #ifndef MIR_REDUCE_H */
|
@ -0,0 +1,170 @@
|
||||
/* This file is a part of MIR project.
|
||||
Copyright (C) 2018, 2019 Vladimir Makarov <vmakarov.gcc@gmail.com>.
|
||||
*/
|
||||
|
||||
#ifndef MIR_VARR_H
|
||||
#define MIR_VARR_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#if !defined(VARR_ENABLE_CHECKING) && !defined(NDEBUG)
|
||||
#define VARR_ENABLE_CHECKING
|
||||
#endif
|
||||
|
||||
#ifndef VARR_ENABLE_CHECKING
|
||||
#define VARR_ASSERT(EXPR, OP, T) ((void) (EXPR))
|
||||
|
||||
#else
|
||||
static inline void mir_var_assert_fail (const char *op, const char *var) {
|
||||
fprintf (stderr, "wrong %s for %s", op, var);
|
||||
assert (0);
|
||||
}
|
||||
|
||||
#define VARR_ASSERT(EXPR, OP, T) (void) ((EXPR) ? 0 : (mir_var_assert_fail (OP, #T), 0))
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define MIR_VARR_NO_RETURN __attribute__ ((noreturn))
|
||||
#else
|
||||
#define MIR_VARR_NO_RETURN
|
||||
#endif
|
||||
|
||||
static inline void MIR_VARR_NO_RETURN mir_varr_error (const char *message) {
|
||||
#ifdef MIR_VARR_ERROR
|
||||
MIR_VARR_ERROR (message);
|
||||
assert (0);
|
||||
#else
|
||||
fprintf (stderr, "%s\n", message);
|
||||
#endif
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/*---------------- Typed variable length arrays -----------------------------*/
|
||||
#define VARR_CONCAT2(A, B) A##B
|
||||
#define VARR_CONCAT3(A, B, C) A##B##C
|
||||
#define VARR(T) VARR_CONCAT2 (VARR_, T)
|
||||
#define VARR_OP(T, OP) VARR_CONCAT3 (VARR_, T, OP)
|
||||
|
||||
#define VARR_T(T) \
|
||||
typedef struct VARR (T) { \
|
||||
size_t els_num; \
|
||||
size_t size; \
|
||||
T *varr; \
|
||||
} VARR (T)
|
||||
|
||||
#define VARR_DEFAULT_SIZE 64
|
||||
|
||||
/* Vector of pointer to object. */
|
||||
#define DEF_VARR(T) \
|
||||
VARR_T (T); \
|
||||
\
|
||||
static inline void VARR_OP (T, create) (VARR (T) * *varr, size_t size) { \
|
||||
VARR (T) * va; \
|
||||
if (size == 0) size = VARR_DEFAULT_SIZE; \
|
||||
*varr = va = (VARR (T) *) malloc (sizeof (VARR (T))); \
|
||||
if (va == NULL) mir_varr_error ("varr: no memory"); \
|
||||
va->els_num = 0; \
|
||||
va->size = size; \
|
||||
va->varr = (T *) malloc (size * sizeof (T)); \
|
||||
} \
|
||||
\
|
||||
static inline void VARR_OP (T, destroy) (VARR (T) * *varr) { \
|
||||
VARR (T) *va = *varr; \
|
||||
VARR_ASSERT (va && va->varr, "destroy", T); \
|
||||
free (va->varr); \
|
||||
free (va); \
|
||||
*varr = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline size_t VARR_OP (T, length) (const VARR (T) * varr) { \
|
||||
VARR_ASSERT (varr, "length", T); \
|
||||
return varr->els_num; \
|
||||
} \
|
||||
\
|
||||
static inline T *VARR_OP (T, addr) (const VARR (T) * varr) { \
|
||||
VARR_ASSERT (varr, "addr", T); \
|
||||
return &varr->varr[0]; \
|
||||
} \
|
||||
\
|
||||
static inline T VARR_OP (T, last) (const VARR (T) * varr) { \
|
||||
VARR_ASSERT (varr && varr->varr && varr->els_num, "last", T); \
|
||||
return varr->varr[varr->els_num - 1]; \
|
||||
} \
|
||||
\
|
||||
static inline T VARR_OP (T, get) (const VARR (T) * varr, unsigned ix) { \
|
||||
VARR_ASSERT (varr && varr->varr && ix < varr->els_num, "get", T); \
|
||||
return varr->varr[ix]; \
|
||||
} \
|
||||
\
|
||||
static inline T VARR_OP (T, set) (const VARR (T) * varr, unsigned ix, T obj) { \
|
||||
T old_obj; \
|
||||
VARR_ASSERT (varr && varr->varr && ix < varr->els_num, "set", T); \
|
||||
old_obj = varr->varr[ix]; \
|
||||
varr->varr[ix] = obj; \
|
||||
return old_obj; \
|
||||
} \
|
||||
\
|
||||
static inline void VARR_OP (T, trunc) (VARR (T) * varr, size_t size) { \
|
||||
VARR_ASSERT (varr && varr->varr && varr->els_num >= size, "trunc", T); \
|
||||
varr->els_num = size; \
|
||||
} \
|
||||
\
|
||||
static inline int VARR_OP (T, expand) (VARR (T) * varr, size_t size) { \
|
||||
VARR_ASSERT (varr && varr->varr, "expand", T); \
|
||||
if (varr->size < size) { \
|
||||
size += size / 2; \
|
||||
varr->varr = (T *) realloc (varr->varr, sizeof (T) * size); \
|
||||
varr->size = size; \
|
||||
return 1; \
|
||||
} \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
static inline void VARR_OP (T, tailor) (VARR (T) * varr, size_t size) { \
|
||||
VARR_ASSERT (varr && varr->varr, "tailor", T); \
|
||||
if (varr->size != size) varr->varr = (T *) realloc (varr->varr, sizeof (T) * size); \
|
||||
varr->els_num = varr->size = size; \
|
||||
} \
|
||||
\
|
||||
static inline void VARR_OP (T, push) (VARR (T) * varr, T obj) { \
|
||||
T *slot; \
|
||||
VARR_OP (T, expand) (varr, varr->els_num + 1); \
|
||||
slot = &varr->varr[varr->els_num++]; \
|
||||
*slot = obj; \
|
||||
} \
|
||||
\
|
||||
static inline void VARR_OP (T, push_arr) (VARR (T) * varr, const T *objs, size_t len) { \
|
||||
size_t i; \
|
||||
T *slot; \
|
||||
VARR_OP (T, expand) (varr, varr->els_num + len); \
|
||||
for (i = 0; i < len; i++) { \
|
||||
slot = &varr->varr[varr->els_num++]; \
|
||||
*slot = objs[i]; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline T VARR_OP (T, pop) (VARR (T) * varr) { \
|
||||
T obj; \
|
||||
VARR_ASSERT (varr && varr->varr && varr->els_num, "pop", T); \
|
||||
obj = varr->varr[--varr->els_num]; \
|
||||
return obj; \
|
||||
}
|
||||
|
||||
#define VARR_CREATE(T, V, L) (VARR_OP (T, create) (&(V), L))
|
||||
#define VARR_DESTROY(T, V) (VARR_OP (T, destroy) (&(V)))
|
||||
#define VARR_LENGTH(T, V) (VARR_OP (T, length) (V))
|
||||
#define VARR_ADDR(T, V) (VARR_OP (T, addr) (V))
|
||||
#define VARR_LAST(T, V) (VARR_OP (T, last) (V))
|
||||
#define VARR_GET(T, V, I) (VARR_OP (T, get) (V, I))
|
||||
#define VARR_SET(T, V, I, O) (VARR_OP (T, set) (V, I, O))
|
||||
#define VARR_TRUNC(T, V, S) (VARR_OP (T, trunc) (V, S))
|
||||
#define VARR_EXPAND(T, V, S) (VARR_OP (T, expand) (V, S))
|
||||
#define VARR_TAILOR(T, V, S) (VARR_OP (T, tailor) (V, S))
|
||||
#define VARR_PUSH(T, V, O) (VARR_OP (T, push) (V, O))
|
||||
#define VARR_PUSH_ARR(T, V, A, L) (VARR_OP (T, push_arr) (V, A, L))
|
||||
#define VARR_POP(T, V) (VARR_OP (T, pop) (V))
|
||||
|
||||
#endif /* #ifndef MIR_VARR_H */
|
@ -0,0 +1,355 @@
|
||||
/* This file is a part of MIR project.
|
||||
Copyright (C) 2018, 2019 Vladimir Makarov <vmakarov.gcc@gmail.com>.
|
||||
*/
|
||||
|
||||
void *_MIR_get_bstart_builtin (MIR_context_t ctx) {
|
||||
static const uint8_t bstart_code[] = {
|
||||
0x48, 0x8d, 0x44, 0x24, 0x08, /* rax = rsp + 8 (lea) */
|
||||
0xc3, /* ret */
|
||||
};
|
||||
return _MIR_publish_code (ctx, bstart_code, sizeof (bstart_code));
|
||||
}
|
||||
void *_MIR_get_bend_builtin (MIR_context_t ctx) {
|
||||
static const uint8_t bend_code[] = {
|
||||
0x48, 0x8b, 0x04, 0x24, /* rax = (rsp) */
|
||||
0x48, 0x89, 0xfc, /* rsp = rdi */
|
||||
0xff, 0xe0, /* jmp *rax */
|
||||
};
|
||||
return _MIR_publish_code (ctx, bend_code, sizeof (bend_code));
|
||||
}
|
||||
|
||||
struct x86_64_va_list {
|
||||
uint32_t gp_offset, fp_offset;
|
||||
uint64_t *overflow_arg_area, *reg_save_area;
|
||||
};
|
||||
|
||||
void *va_arg_builtin (void *p, uint64_t t) {
|
||||
struct x86_64_va_list *va = p;
|
||||
MIR_type_t type = t;
|
||||
int fp_p = type == MIR_T_F || type == MIR_T_D;
|
||||
void *a;
|
||||
|
||||
if (fp_p && va->fp_offset <= 160) {
|
||||
a = (char *) va->reg_save_area + va->fp_offset;
|
||||
va->fp_offset += 16;
|
||||
} else if (!fp_p && type != MIR_T_LD && va->gp_offset <= 40) {
|
||||
a = (char *) va->reg_save_area + va->gp_offset;
|
||||
va->gp_offset += 8;
|
||||
} else {
|
||||
a = va->overflow_arg_area;
|
||||
va->overflow_arg_area += type == MIR_T_LD ? 2 : 1;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
void va_start_interp_builtin (MIR_context_t ctx, void *p, void *a) {
|
||||
struct x86_64_va_list *va = p;
|
||||
va_list *vap = a;
|
||||
|
||||
assert (sizeof (struct x86_64_va_list) == sizeof (va_list));
|
||||
*va = *(struct x86_64_va_list *) vap;
|
||||
}
|
||||
|
||||
void va_end_interp_builtin (MIR_context_t ctx, void *p) {}
|
||||
|
||||
/* r11=<address to go to>; jump *r11 */
|
||||
void *_MIR_get_thunk (MIR_context_t ctx) {
|
||||
void *res;
|
||||
static const uint8_t pattern[] = {
|
||||
0x49, 0xbb, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0: movabsq 0, r11 */
|
||||
0x41, 0xff, 0xe3, /* 0x14: jmpq *%r11 */
|
||||
};
|
||||
res = _MIR_publish_code (ctx, pattern, sizeof (pattern));
|
||||
return res;
|
||||
}
|
||||
|
||||
void _MIR_redirect_thunk (MIR_context_t ctx, void *thunk, void *to) {
|
||||
_MIR_update_code (ctx, thunk, 1, 2, to);
|
||||
}
|
||||
|
||||
static const uint8_t save_pat[] = {
|
||||
0x48, 0x81, 0xec, 0x80, 0, 0, 0, /*sub $0x80,%rsp */
|
||||
0xf3, 0x0f, 0x7f, 0x04, 0x24, /*movdqu %xmm0,(%rsp) */
|
||||
0xf3, 0x0f, 0x7f, 0x4c, 0x24, 0x10, /*movdqu %xmm1,0x10(%rsp) */
|
||||
0xf3, 0x0f, 0x7f, 0x54, 0x24, 0x20, /*movdqu %xmm2,0x20(%rsp) */
|
||||
0xf3, 0x0f, 0x7f, 0x5c, 0x24, 0x30, /*movdqu %xmm3,0x30(%rsp) */
|
||||
0xf3, 0x0f, 0x7f, 0x64, 0x24, 0x40, /*movdqu %xmm4,0x40(%rsp) */
|
||||
0xf3, 0x0f, 0x7f, 0x6c, 0x24, 0x50, /*movdqu %xmm5,0x50(%rsp) */
|
||||
0xf3, 0x0f, 0x7f, 0x74, 0x24, 0x60, /*movdqu %xmm6,0x60(%rsp) */
|
||||
0xf3, 0x0f, 0x7f, 0x7c, 0x24, 0x70, /*movdqu %xmm7,0x70(%rsp) */
|
||||
0x41, 0x51, /*push %r9 */
|
||||
0x41, 0x50, /*push %r8 */
|
||||
0x51, /*push %rcx */
|
||||
0x52, /*push %rdx */
|
||||
0x56, /*push %rsi */
|
||||
0x57, /*push %rdi */
|
||||
};
|
||||
|
||||
static const uint8_t restore_pat[] = {
|
||||
0x5f, /*pop %rdi */
|
||||
0x5e, /*pop %rsi */
|
||||
0x5a, /*pop %rdx */
|
||||
0x59, /*pop %rcx */
|
||||
0x41, 0x58, /*pop %r8 */
|
||||
0x41, 0x59, /*pop %r9 */
|
||||
0xf3, 0x0f, 0x6f, 0x04, 0x24, /*movdqu (%rsp),%xmm0 */
|
||||
0xf3, 0x0f, 0x6f, 0x4c, 0x24, 0x10, /*movdqu 0x10(%rsp),%xmm1 */
|
||||
0xf3, 0x0f, 0x6f, 0x54, 0x24, 0x20, /*movdqu 0x20(%rsp),%xmm2 */
|
||||
0xf3, 0x0f, 0x6f, 0x5c, 0x24, 0x30, /*movdqu 0x30(%rsp),%xmm3 */
|
||||
0xf3, 0x0f, 0x6f, 0x64, 0x24, 0x40, /*movdqu 0x40(%rsp),%xmm4 */
|
||||
0xf3, 0x0f, 0x6f, 0x6c, 0x24, 0x50, /*movdqu 0x50(%rsp),%xmm5 */
|
||||
0xf3, 0x0f, 0x6f, 0x74, 0x24, 0x60, /*movdqu 0x60(%rsp),%xmm6 */
|
||||
0xf3, 0x0f, 0x6f, 0x7c, 0x24, 0x70, /*movdqu 0x70(%rsp),%xmm7 */
|
||||
0x48, 0x81, 0xc4, 0x80, 0, 0, 0, /*add $0x80,%rsp */
|
||||
};
|
||||
|
||||
VARR (uint8_t) * machine_insns;
|
||||
|
||||
static uint8_t *push_insns (const uint8_t *pat, size_t pat_len) {
|
||||
for (size_t i = 0; i < pat_len; i++) VARR_PUSH (uint8_t, machine_insns, pat[i]);
|
||||
return VARR_ADDR (uint8_t, machine_insns) + VARR_LENGTH (uint8_t, machine_insns) - pat_len;
|
||||
}
|
||||
|
||||
static void gen_mov (uint32_t offset, uint32_t reg, int ld_p) {
|
||||
static const uint8_t ld_gp_reg[] = {0x48, 0x8b, 0x83, 0, 0, 0, 0 /* mov <offset>(%rbx),%reg */};
|
||||
static const uint8_t st_gp_reg[] = {0x48, 0x89, 0x83, 0, 0, 0, 0 /* mov %reg,<offset>(%rbx) */};
|
||||
uint8_t *addr
|
||||
= push_insns (ld_p ? ld_gp_reg : st_gp_reg, ld_p ? sizeof (ld_gp_reg) : sizeof (st_gp_reg));
|
||||
memcpy (addr + 3, &offset, sizeof (uint32_t));
|
||||
assert (reg <= 15);
|
||||
addr[0] |= (reg >> 1) & 4;
|
||||
addr[2] |= (reg & 7) << 3;
|
||||
}
|
||||
|
||||
static void gen_movxmm (uint32_t offset, uint32_t reg, int b32_p, int ld_p) {
|
||||
static const uint8_t ld_xmm_reg_pat[] = {
|
||||
0xf2, 0x0f, 0x10, 0x83, 0, 0, 0, 0 /* movs[sd] <offset>(%rbx),%xmm */
|
||||
};
|
||||
static const uint8_t st_xmm_reg_pat[] = {
|
||||
0xf2, 0x0f, 0x11, 0x83, 0, 0, 0, 0 /* movs[sd] %xmm, <offset>(%rbx) */
|
||||
};
|
||||
uint8_t *addr = push_insns (ld_p ? ld_xmm_reg_pat : st_xmm_reg_pat,
|
||||
ld_p ? sizeof (ld_xmm_reg_pat) : sizeof (st_xmm_reg_pat));
|
||||
memcpy (addr + 4, &offset, sizeof (uint32_t));
|
||||
assert (reg <= 7);
|
||||
addr[3] |= reg << 3;
|
||||
if (b32_p) addr[0] |= 1;
|
||||
}
|
||||
|
||||
static void gen_ldst (uint32_t sp_offset, uint32_t src_offset, int b64_p) {
|
||||
static const uint8_t ldst_pat[] = {
|
||||
0x44, 0x8b, 0x93, 0, 0, 0, 0, /* mov <src_offset>(%rbx),%r10 */
|
||||
0x44, 0x89, 0x94, 0x24, 0, 0, 0, 0, /* mov %r10,<sp_offset>(%sp) */
|
||||
};
|
||||
uint8_t *addr = push_insns (ldst_pat, sizeof (ldst_pat));
|
||||
memcpy (addr + 3, &src_offset, sizeof (uint32_t));
|
||||
memcpy (addr + 11, &sp_offset, sizeof (uint32_t));
|
||||
if (b64_p) {
|
||||
addr[0] |= 8;
|
||||
addr[7] |= 8;
|
||||
}
|
||||
}
|
||||
|
||||
static void gen_ldst80 (uint32_t sp_offset, uint32_t src_offset) {
|
||||
static uint8_t const ldst80_pat[] = {
|
||||
0xdb, 0xab, 0, 0, 0, 0, /* fldt <src_offset>(%rbx) */
|
||||
0xdb, 0xbc, 0x24, 0, 0, 0, 0, /* fstpt <sp_offset>(%sp) */
|
||||
};
|
||||
uint8_t *addr = push_insns (ldst80_pat, sizeof (ldst80_pat));
|
||||
memcpy (addr + 2, &src_offset, sizeof (uint32_t));
|
||||
memcpy (addr + 9, &sp_offset, sizeof (uint32_t));
|
||||
}
|
||||
|
||||
static void gen_st80 (uint32_t src_offset) {
|
||||
static const uint8_t st80_pat[] = {0xdb, 0xbb, 0, 0, 0, 0 /* fstpt <src_offset>(%rbx) */};
|
||||
memcpy (push_insns (st80_pat, sizeof (st80_pat)) + 2, &src_offset, sizeof (uint32_t));
|
||||
}
|
||||
|
||||
/* Generation: fun (fun_addr, res_arg_addresses):
|
||||
push rbx; sp-=sp_offset; r11=fun_addr; rbx=res/arg_addrs
|
||||
r10=mem[rbx,<offset>]; (arg_reg=mem[r10] or r10=mem[r10];mem[sp,sp_offset]=r10) ...
|
||||
rax=8; call *r11; sp+=offset
|
||||
r10=mem[rbx,<offset>]; res_reg=mem[r10]; ...
|
||||
pop rbx; ret. */
|
||||
void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, size_t nargs,
|
||||
MIR_type_t *arg_types) {
|
||||
static const uint8_t prolog[] = {
|
||||
0x53, /* pushq %rbx */
|
||||
0x48, 0x81, 0xec, 0, 0, 0, 0, /* subq <sp_offset>, %rsp */
|
||||
0x49, 0x89, 0xfb, /* mov $rdi, $r11 -- fun addr */
|
||||
0x48, 0x89, 0xf3, /* mov $rsi, $rbx -- result/arg addresses */
|
||||
};
|
||||
static const uint8_t call_end[] = {
|
||||
0x48, 0xc7, 0xc0, 0x08, 0, 0, 0, /* mov $8, rax -- to save xmm varargs */
|
||||
0x41, 0xff, 0xd3, /* callq *%r11 */
|
||||
0x48, 0x81, 0xc4, 0, 0, 0, 0, /* addq <sp_offset>, %rsp */
|
||||
};
|
||||
static const uint8_t epilog[] = {
|
||||
0x5b, /* pop %rbx */
|
||||
0xc3, /* ret */
|
||||
};
|
||||
static const uint8_t iregs[] = {7, 6, 2, 1, 8, 9}; /* rdi, rsi, rdx, rcx, r8, r9 */
|
||||
uint32_t n_iregs = 0, n_xregs = 0, n_fregs, sp_offset = 0;
|
||||
uint8_t *addr;
|
||||
|
||||
VARR_TRUNC (uint8_t, machine_insns, 0);
|
||||
push_insns (prolog, sizeof (prolog));
|
||||
for (size_t i = 0; i < nargs; i++) {
|
||||
if ((MIR_T_I8 <= arg_types[i] && arg_types[i] <= MIR_T_U64) || arg_types[i] == MIR_T_P) {
|
||||
if (n_iregs < 6) {
|
||||
gen_mov ((i + nres) * sizeof (long double), iregs[n_iregs++], TRUE);
|
||||
} else {
|
||||
gen_ldst (sp_offset, (i + nres) * sizeof (long double), TRUE);
|
||||
sp_offset += 8;
|
||||
}
|
||||
} else if (arg_types[i] == MIR_T_F || arg_types[i] == MIR_T_D) {
|
||||
if (n_xregs < 8) {
|
||||
gen_movxmm ((i + nres) * sizeof (long double), n_xregs++, arg_types[i] == MIR_T_F, TRUE);
|
||||
} else {
|
||||
gen_ldst (sp_offset, (i + nres) * sizeof (long double), arg_types[i] == MIR_T_D);
|
||||
sp_offset += 8;
|
||||
}
|
||||
} else if (arg_types[i] == MIR_T_LD) {
|
||||
gen_ldst80 (sp_offset, (i + nres) * sizeof (long double));
|
||||
sp_offset += 16;
|
||||
} else {
|
||||
(*error_func) (MIR_call_op_error, "wrong type of arg value");
|
||||
}
|
||||
}
|
||||
sp_offset = (sp_offset + 15) / 16 * 16;
|
||||
addr = VARR_ADDR (uint8_t, machine_insns);
|
||||
memcpy (addr + 4, &sp_offset, sizeof (uint32_t));
|
||||
addr = push_insns (call_end, sizeof (call_end));
|
||||
memcpy (addr + 13, &sp_offset, sizeof (uint32_t));
|
||||
n_iregs = n_xregs = n_fregs = 0;
|
||||
for (size_t i = 0; i < nres; i++) {
|
||||
if (((MIR_T_I8 <= res_types[i] && res_types[i] <= MIR_T_U64) || res_types[i] == MIR_T_P)
|
||||
&& n_iregs < 2) {
|
||||
gen_mov (i * sizeof (long double), n_iregs++ == 0 ? 0 : 2, FALSE); /* rax or rdx */
|
||||
} else if ((res_types[i] == MIR_T_F || res_types[i] == MIR_T_D) && n_xregs < 2) {
|
||||
gen_movxmm (i * sizeof (long double), n_xregs++, res_types[i] == MIR_T_F, FALSE);
|
||||
} else if (res_types[i] == MIR_T_LD && n_fregs < 2) {
|
||||
gen_st80 (i * sizeof (long double));
|
||||
} else {
|
||||
(*error_func) (MIR_ret_error, "x86-64 can not handle this combination of return values");
|
||||
}
|
||||
}
|
||||
push_insns (epilog, sizeof (epilog));
|
||||
return _MIR_publish_code (ctx, VARR_ADDR (uint8_t, machine_insns),
|
||||
VARR_LENGTH (uint8_t, machine_insns));
|
||||
}
|
||||
|
||||
void *_MIR_get_interp_shim (MIR_context_t ctx, MIR_item_t func_item, void *handler) {
|
||||
static const uint8_t push_rbx[] = {0x53, /*push %rbx */};
|
||||
static const uint8_t prepare_pat[] = {
|
||||
/* 0: */ 0x48, 0x83, 0xec, 0x20, /* sub 32,%rsp */
|
||||
/* 4: */ 0x48, 0x89, 0xe2, /* mov %rsp,%rdx */
|
||||
/* 7: */ 0xc7, 0x02, 0, 0, 0, 0, /* movl 0,(%rdx) */
|
||||
/* d: */ 0xc7, 0x42, 0x04, 0x30, 0, 0, 0, /* movl 48, 4(%rdx) */
|
||||
/* 14: */ 0x48, 0x8d, 0x44, 0x24, 0x20, /* lea 32(%rsp),%rax */
|
||||
/* 19: */ 0x48, 0x89, 0x42, 0x10, /* mov %rax,16(%rdx) */
|
||||
/* 1d: */ 0x48, 0x8d, 0x84, 0x24, 0xe0, 0, 0, 0, /* lea 224(%rsp),%rax */
|
||||
/* 25: */ 0x48, 0x89, 0x42, 0x08, /* mov %rax,8(%rdx) */
|
||||
/* 29: */ 0x48, 0x81, 0xec, 0, 0, 0, 0, /* sub <n>,%rsp */
|
||||
/* 30: */ 0x48, 0x89, 0xe3, /* mov %rsp,%rbx */
|
||||
/* 33: */ 0x48, 0x89, 0xe1, /* mov %rsp,%rcx */
|
||||
/* 36: */ 0x48, 0xbf, 0, 0, 0, 0, 0, 0, 0, 0, /* movabs <ctx>,%rdi */
|
||||
/* 40: */ 0x48, 0xbe, 0, 0, 0, 0, 0, 0, 0, 0, /* movabs <func_item>,%rsi */
|
||||
/* 4a: */ 0x48, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, /* movabs <handler>,%rax */
|
||||
/* 54: */ 0xff, 0xd0, /* callq *%rax */
|
||||
};
|
||||
static const uint8_t shim_end[] = {
|
||||
/* 0: */ 0x48, 0x81, 0xc4, 0, 0, 0, 0, /*add 208+n,%rsp*/
|
||||
/* 7: */ 0x5b, /*pop %rbx*/
|
||||
/* 8: */ 0xc3, /*retq */
|
||||
};
|
||||
static const uint8_t ld_pat[]
|
||||
= {0x48, 0x8b, 0x83, 0, 0, 0, 0}; /* movss <offset>(%rbx), %xmm[01] */
|
||||
static const uint8_t movss_pat[]
|
||||
= {0xf3, 0x0f, 0x10, 0x83, 0, 0, 0, 0}; /* movss <offset>(%rbx), %xmm[01] */
|
||||
static const uint8_t movsd_pat[]
|
||||
= {0xf2, 0x0f, 0x10, 0x83, 0, 0, 0, 0}; /* movsd <offset>(%rbx), %xmm[01] */
|
||||
static const uint8_t fldt_pat[] = {0xdb, 0xab, 0, 0, 0, 0}; /* fldt <offset>(%rbx) */
|
||||
static const uint8_t fxch_pat[] = {0xd9, 0xc9}; /* fxch */
|
||||
uint8_t *addr;
|
||||
uint32_t imm, n_iregs, n_xregs, n_fregs, offset;
|
||||
uint32_t nres = func_item->u.func->nres;
|
||||
MIR_type_t *results = func_item->u.func->res_types;
|
||||
|
||||
VARR_TRUNC (uint8_t, machine_insns, 0);
|
||||
push_insns (push_rbx, sizeof (push_rbx));
|
||||
push_insns (save_pat, sizeof (save_pat));
|
||||
addr = push_insns (prepare_pat, sizeof (prepare_pat));
|
||||
imm = nres * 16;
|
||||
memcpy (addr + 0x2c, &imm, sizeof (uint32_t));
|
||||
memcpy (addr + 0x38, &ctx, sizeof (void *));
|
||||
memcpy (addr + 0x42, &func_item, sizeof (void *));
|
||||
memcpy (addr + 0x4c, &handler, sizeof (void *));
|
||||
/* move results: */
|
||||
n_iregs = n_xregs = n_fregs = offset = 0;
|
||||
for (uint32_t i = 0; i < nres; i++) {
|
||||
if (results[i] == MIR_T_F && n_xregs < 2) {
|
||||
addr = push_insns (movss_pat, sizeof (movss_pat));
|
||||
addr[3] |= n_xregs << 3;
|
||||
memcpy (addr + 4, &offset, sizeof (uint32_t));
|
||||
n_xregs++;
|
||||
} else if (results[i] == MIR_T_D && n_xregs < 2) {
|
||||
addr = push_insns (movsd_pat, sizeof (movsd_pat));
|
||||
addr[3] |= n_xregs << 3;
|
||||
memcpy (addr + 4, &offset, sizeof (uint32_t));
|
||||
n_xregs++;
|
||||
} else if (results[i] == MIR_T_LD && n_fregs < 2) {
|
||||
addr = push_insns (fldt_pat, sizeof (fldt_pat));
|
||||
memcpy (addr + 2, &offset, sizeof (uint32_t));
|
||||
if (n_fregs == 1) push_insns (fxch_pat, sizeof (fxch_pat));
|
||||
n_fregs++;
|
||||
} else if (n_iregs < 2) {
|
||||
addr = push_insns (ld_pat, sizeof (ld_pat));
|
||||
addr[2] |= n_iregs << 4;
|
||||
memcpy (addr + 3, &offset, sizeof (uint32_t));
|
||||
n_iregs++;
|
||||
} else {
|
||||
(*error_func) (MIR_ret_error, "x86-64 can not handle this combination of return values");
|
||||
}
|
||||
offset += 16;
|
||||
}
|
||||
addr = push_insns (shim_end, sizeof (shim_end));
|
||||
imm = 208 + nres * 16;
|
||||
memcpy (addr + 3, &imm, sizeof (uint32_t));
|
||||
return _MIR_publish_code (ctx, VARR_ADDR (uint8_t, machine_insns),
|
||||
VARR_LENGTH (uint8_t, machine_insns));
|
||||
}
|
||||
|
||||
/* save regs; r10 = call hook_address (ctx, called_func); restore regs; jmp *r10
|
||||
*/
|
||||
void *_MIR_get_wrapper (MIR_context_t ctx, MIR_item_t called_func, void *hook_address) {
|
||||
static const uint8_t push_rax[] = {0x50, /*push %rax */};
|
||||
static const uint8_t wrap_end[] = {
|
||||
0x58, /*pop %rax */
|
||||
0x41, 0xff, 0xe2, /*jmpq *%r10 */
|
||||
};
|
||||
static const uint8_t call_pat[] = {
|
||||
0x48, 0xbe, 0, 0, 0, 0, 0, 0, 0, 0, /*movabs called_func,%rsi */
|
||||
0x48, 0xbf, 0, 0, 0, 0, 0, 0, 0, 0, /*movabs ctx,%rdi */
|
||||
0x49, 0xba, 0, 0, 0, 0, 0, 0, 0, 0, /*movabs <hook_address>,%r10 */
|
||||
0x41, 0xff, 0xd2, /*callq *%r10 */
|
||||
0x49, 0x89, 0xc2, /*mov %rax,%r10 */
|
||||
};
|
||||
uint8_t *addr;
|
||||
|
||||
VARR_TRUNC (uint8_t, machine_insns, 0);
|
||||
push_insns (push_rax, sizeof (push_rax));
|
||||
push_insns (save_pat, sizeof (save_pat));
|
||||
addr = push_insns (call_pat, sizeof (call_pat));
|
||||
memcpy (addr + 2, &called_func, sizeof (void *));
|
||||
memcpy (addr + 12, &ctx, sizeof (void *));
|
||||
memcpy (addr + 22, &hook_address, sizeof (void *));
|
||||
push_insns (restore_pat, sizeof (restore_pat));
|
||||
push_insns (wrap_end, sizeof (wrap_end));
|
||||
return _MIR_publish_code (ctx, VARR_ADDR (uint8_t, machine_insns),
|
||||
VARR_LENGTH (uint8_t, machine_insns));
|
||||
}
|
||||
|
||||
static void machine_init (MIR_context_t ctx) { VARR_CREATE (uint8_t, machine_insns, 1024); }
|
||||
|
||||
static void machine_finish (MIR_context_t ctx) { VARR_DESTROY (uint8_t, machine_insns); }
|
@ -0,0 +1,584 @@
|
||||
/* This file is a part of MIR project.
|
||||
Copyright (C) 2018, 2019 Vladimir Makarov <vmakarov.gcc@gmail.com>.
|
||||
*/
|
||||
|
||||
#ifndef MIR_H
|
||||
|
||||
#define MIR_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include "mir-dlist.h"
|
||||
#include "mir-varr.h"
|
||||
#include "mir-htab.h"
|
||||
|
||||
#ifdef NDEBUG
|
||||
static inline int mir_assert (int cond) { return 0 && cond; }
|
||||
#else
|
||||
#define mir_assert(cond) assert (cond)
|
||||
#endif
|
||||
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
|
||||
/* Redefine MIR_NO_IO or/and MIR_NO_SCAN if you don't need the functionality they provide. */
|
||||
#ifndef MIR_NO_IO
|
||||
#define MIR_NO_IO 0
|
||||
#endif
|
||||
|
||||
#ifndef MIR_NO_SCAN
|
||||
#define MIR_NO_SCAN 0
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define MIR_UNUSED __attribute__ ((unused))
|
||||
#else
|
||||
#define MIR_UNUSED
|
||||
#endif
|
||||
|
||||
#define REP2(M, a1, a2) M (a1) REP_SEP M (a2)
|
||||
#define REP3(M, a1, a2, a3) REP2 (M, a1, a2) REP_SEP M (a3)
|
||||
#define REP4(M, a1, a2, a3, a4) REP3 (M, a1, a2, a3) REP_SEP M (a4)
|
||||
#define REP5(M, a1, a2, a3, a4, a5) REP4 (M, a1, a2, a3, a4) REP_SEP M (a5)
|
||||
#define REP6(M, a1, a2, a3, a4, a5, a6) REP5 (M, a1, a2, a3, a4, a5) REP_SEP M (a6)
|
||||
#define REP7(M, a1, a2, a3, a4, a5, a6, a7) REP6 (M, a1, a2, a3, a4, a5, a6) REP_SEP M (a7)
|
||||
#define REP8(M, a1, a2, a3, a4, a5, a6, a7, a8) REP7 (M, a1, a2, a3, a4, a5, a6, a7) REP_SEP M (a8)
|
||||
|
||||
#define REP_SEP ,
|
||||
|
||||
#define ERR_EL(e) MIR_##e##_error
|
||||
typedef enum MIR_error_type {
|
||||
REP8 (ERR_EL, no, syntax, binary_io, alloc, finish, no_module, nested_module, no_func),
|
||||
REP4 (ERR_EL, func, vararg_func, nested_func, wrong_param_value),
|
||||
REP4 (ERR_EL, reserved_name, import_export, undeclared_func_reg, repeated_decl),
|
||||
REP8 (ERR_EL, reg_type, unique_reg, undeclared_op_ref, ops_num, call_op, ret, op_mode, out_op),
|
||||
ERR_EL (invalid_insn)
|
||||
} MIR_error_type_t;
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define MIR_NO_RETURN __attribute__ ((noreturn))
|
||||
#else
|
||||
#define MIR_NO_RETURN
|
||||
#endif
|
||||
|
||||
typedef void MIR_NO_RETURN (*MIR_error_func_t) (MIR_error_type_t error_type, const char *format,
|
||||
...);
|
||||
|
||||
#define INSN_EL(i) MIR_##i
|
||||
|
||||
/* The most MIR insns have destination operand and one or two source
|
||||
operands. The destination can be ony a register or memory.
|
||||
|
||||
There are additional constraints on insn operands:
|
||||
|
||||
o A register in porgram can contain only one type values: integer,
|
||||
float, double, or long double.
|
||||
o Operand types should be what the insn expects */
|
||||
typedef enum {
|
||||
/* Abbreviations:
|
||||
I - 64-bit int, S - short (32-bit), U - unsigned, F -float, D - double, LD - long double. */
|
||||
/* 2 operand insns: */
|
||||
REP4 (INSN_EL, MOV, FMOV, DMOV, LDMOV), /* Moves */
|
||||
/* Extensions. Truncation is not necessary because we can use an extension to use a part. */
|
||||
REP6 (INSN_EL, EXT8, EXT16, EXT32, UEXT8, UEXT16, UEXT32),
|
||||
REP3 (INSN_EL, I2F, I2D, I2LD), /* Integer to float or (long) double conversion */
|
||||
REP3 (INSN_EL, UI2F, UI2D, UI2LD), /* Unsigned integer to float or (long) double conversion */
|
||||
REP3 (INSN_EL, F2I, D2I, LD2I), /* Float or (long) double to integer conversion */
|
||||
REP6 (INSN_EL, F2D, F2LD, D2F, D2LD, LD2F, LD2D), /* Float, (long) double conversions */
|
||||
REP5 (INSN_EL, NEG, NEGS, FNEG, DNEG, LDNEG), /* Changing sign */
|
||||
/* 3 operand insn: */
|
||||
REP5 (INSN_EL, ADD, ADDS, FADD, DADD, LDADD), /* Addition */
|
||||
REP5 (INSN_EL, SUB, SUBS, FSUB, DSUB, LDSUB), /* Subtraction */
|
||||
REP5 (INSN_EL, MUL, MULS, FMUL, DMUL, LDMUL), /* Multiplication */
|
||||
REP7 (INSN_EL, DIV, DIVS, UDIV, UDIVS, FDIV, DDIV, LDDIV), /* Division */
|
||||
REP4 (INSN_EL, MOD, MODS, UMOD, UMODS), /* Modulo */
|
||||
REP6 (INSN_EL, AND, ANDS, OR, ORS, XOR, XORS), /* Logical */
|
||||
REP6 (INSN_EL, LSH, LSHS, RSH, RSHS, URSH, URSHS), /* Right signed/unsigned shift */
|
||||
REP5 (INSN_EL, EQ, EQS, FEQ, DEQ, LDEQ), /* Equality */
|
||||
REP5 (INSN_EL, NE, NES, FNE, DNE, LDNE), /* Inequality */
|
||||
REP7 (INSN_EL, LT, LTS, ULT, ULTS, FLT, DLT, LDLT), /* Less then */
|
||||
REP7 (INSN_EL, LE, LES, ULE, ULES, FLE, DLE, LDLE), /* Less or equal */
|
||||
REP7 (INSN_EL, GT, GTS, UGT, UGTS, FGT, DGT, LDGT), /* Greater then */
|
||||
REP7 (INSN_EL, GE, GES, UGE, UGES, FGE, DGE, LDGE), /* Greater or equal */
|
||||
/* Uncoditional (1 operand) and conditional (2 operands) branch
|
||||
insns. The first operand is a label. */
|
||||
REP5 (INSN_EL, JMP, BT, BTS, BF, BFS),
|
||||
/* Compare and branch (3 operand) insns. The first operand is the
|
||||
label. */
|
||||
REP5 (INSN_EL, BEQ, BEQS, FBEQ, DBEQ, LDBEQ),
|
||||
REP5 (INSN_EL, BNE, BNES, FBNE, DBNE, LDBNE),
|
||||
REP7 (INSN_EL, BLT, BLTS, UBLT, UBLTS, FBLT, DBLT, LDBLT),
|
||||
REP7 (INSN_EL, BLE, BLES, UBLE, UBLES, FBLE, DBLE, LDBLE),
|
||||
REP7 (INSN_EL, BGT, BGTS, UBGT, UBGTS, FBGT, DBGT, LDBGT),
|
||||
REP7 (INSN_EL, BGE, BGES, UBGE, UBGES, FBGE, DBGE, LDBGE),
|
||||
/* 1st operand is a prototype, 2nd one is ref or op containing func
|
||||
address, 3rd and subsequent ops are optional result (if result in
|
||||
the prototype is not of void type), call arguments. */
|
||||
REP2 (INSN_EL, CALL, INLINE),
|
||||
/* 1st operand is an index, subsequent ops are labels to which goto
|
||||
according the index (1st label has index zero). The insn
|
||||
behaviour is undefined if there is no label for the index. */
|
||||
INSN_EL (SWITCH),
|
||||
/* 1 operand insn: */
|
||||
INSN_EL (RET),
|
||||
INSN_EL (ALLOCA), /* 2 operands: result address and size */
|
||||
REP2 (INSN_EL, BSTART, BEND), /* block start: result addr; block end: addr from block start */
|
||||
/* Special insns: */
|
||||
INSN_EL (VA_ARG), /* result is arg address, operands: va_list addr and memory */
|
||||
INSN_EL (VA_START),
|
||||
INSN_EL (VA_END), /* operand is va_list */
|
||||
INSN_EL (LABEL), /* One immediate operand is unique label number */
|
||||
INSN_EL (INVALID_INSN),
|
||||
INSN_EL (INSN_BOUND), /* Should be the last */
|
||||
} MIR_insn_code_t;
|
||||
|
||||
#define TYPE_EL(t) MIR_T_##t
|
||||
|
||||
/* Data types: */
|
||||
typedef enum {
|
||||
REP8 (TYPE_EL, I8, U8, I16, U16, I32, U32, I64, U64), /* Integer types of different size: */
|
||||
REP3 (TYPE_EL, F, D, LD), /* Float or (long) double type */
|
||||
TYPE_EL (P), /* Pointer */
|
||||
REP2 (TYPE_EL, UNDEF, BOUND),
|
||||
} MIR_type_t;
|
||||
|
||||
#if UINTPTR_MAX == 0xffffffff
|
||||
#define MIR_PTR32 1
|
||||
#define MIR_PTR64 0
|
||||
#elif UINTPTR_MAX == 0xffffffffffffffffu
|
||||
#define MIR_PTR32 0
|
||||
#define MIR_PTR64 1
|
||||
#else
|
||||
#error MIR can work only for 32- or 64-bit targets
|
||||
#endif
|
||||
|
||||
typedef uint8_t MIR_scale_t; /* Index reg scale in memory */
|
||||
|
||||
#define MIR_MAX_SCALE UINT8_MAX
|
||||
|
||||
typedef int64_t MIR_disp_t; /* Address displacement in memory */
|
||||
|
||||
/* Register number (> 0). A register always contain only one type
|
||||
value: integer, float, or (long) double. Register numbers in insn
|
||||
operands can be changed in MIR_finish_func. */
|
||||
typedef uint32_t MIR_reg_t;
|
||||
|
||||
#define MIR_MAX_REG_NUM UINT32_MAX
|
||||
#define MIR_NON_HARD_REG MIR_MAX_REG_NUM
|
||||
|
||||
/* Immediate in immediate moves. */
|
||||
typedef union {
|
||||
int64_t i;
|
||||
uint64_t u;
|
||||
float f;
|
||||
double d;
|
||||
long double ld;
|
||||
} MIR_imm_t;
|
||||
|
||||
/* Memory: mem:type[base + index * scale + disp]. It also can be
|
||||
memory with hard regs but such memory used only internally. An
|
||||
integer type memory value expands to int64_t value when the insn is
|
||||
executed. */
|
||||
typedef struct {
|
||||
MIR_type_t type : 8;
|
||||
MIR_scale_t scale;
|
||||
/* 0 means no reg for memory. MIR_NON_HARD_REG means no reg for
|
||||
hard reg memory. */
|
||||
MIR_reg_t base, index;
|
||||
MIR_disp_t disp;
|
||||
} MIR_mem_t;
|
||||
|
||||
typedef struct MIR_insn *MIR_label_t;
|
||||
|
||||
typedef const char *MIR_name_t;
|
||||
|
||||
#define OP_EL(op) MIR_OP_##op
|
||||
|
||||
/* Operand mode */
|
||||
typedef enum {
|
||||
REP8 (OP_EL, UNDEF, REG, HARD_REG, INT, UINT, FLOAT, DOUBLE, LDOUBLE),
|
||||
REP6 (OP_EL, REF, STR, MEM, HARD_REG_MEM, LABEL, BOUND),
|
||||
} MIR_op_mode_t;
|
||||
|
||||
typedef struct MIR_item *MIR_item_t;
|
||||
|
||||
struct MIR_str {
|
||||
size_t len;
|
||||
const char *s;
|
||||
};
|
||||
|
||||
typedef struct MIR_str MIR_str_t;
|
||||
|
||||
/* An insn operand */
|
||||
typedef struct {
|
||||
void *data; /* Aux data */
|
||||
MIR_op_mode_t mode;
|
||||
/* Defined after MIR_func_finish. Only MIR_OP_INT, MIR_OP_UINT,
|
||||
MIR_OP_FLOAT, MIR_OP_DOUBLE, MIR_OP_LDOUBLE: */
|
||||
MIR_op_mode_t value_mode;
|
||||
union {
|
||||
MIR_reg_t reg;
|
||||
MIR_reg_t hard_reg; /* Used only internally */
|
||||
int64_t i;
|
||||
uint64_t u;
|
||||
float f;
|
||||
double d;
|
||||
long double ld;
|
||||
MIR_item_t ref; /* non-export/non-forward after simplification */
|
||||
MIR_str_t str;
|
||||
MIR_mem_t mem;
|
||||
MIR_mem_t hard_reg_mem; /* Used only internally */
|
||||
MIR_label_t label;
|
||||
} u;
|
||||
} MIR_op_t;
|
||||
|
||||
typedef struct MIR_insn *MIR_insn_t;
|
||||
|
||||
/* Definition of link of double list of insns */
|
||||
DEF_DLIST_LINK (MIR_insn_t);
|
||||
|
||||
struct MIR_insn {
|
||||
void *data; /* Aux data */
|
||||
DLIST_LINK (MIR_insn_t) insn_link;
|
||||
MIR_insn_code_t code : 32;
|
||||
unsigned int nops : 32; /* number of operands */
|
||||
MIR_op_t ops[1];
|
||||
};
|
||||
|
||||
/* Definition of double list of insns */
|
||||
DEF_DLIST (MIR_insn_t, insn_link);
|
||||
|
||||
typedef struct MIR_var {
|
||||
MIR_type_t type;
|
||||
const char *name;
|
||||
} MIR_var_t;
|
||||
|
||||
DEF_VARR (MIR_var_t);
|
||||
|
||||
/* Function definition */
|
||||
typedef struct MIR_func {
|
||||
const char *name;
|
||||
DLIST (MIR_insn_t) insns, original_insns;
|
||||
uint32_t nres, nargs, last_temp_num, n_inlines;
|
||||
MIR_type_t *res_types;
|
||||
char vararg_p; /* flag of variable number of arguments */
|
||||
char expr_p; /* flag of that the func can be used as a linker expression */
|
||||
VARR (MIR_var_t) * vars; /* args and locals but temps */
|
||||
void *machine_code; /* address of generated machine code or NULL */
|
||||
void *call_addr; /* address to call the function, it can be the same as machine_code */
|
||||
} * MIR_func_t;
|
||||
|
||||
typedef struct MIR_proto {
|
||||
const char *name;
|
||||
uint32_t nres;
|
||||
MIR_type_t *res_types; /* != MIR_T_UNDEF */
|
||||
char vararg_p; /* flag of variable number of arguments */
|
||||
VARR (MIR_var_t) * args; /* args name can be NULL */
|
||||
} * MIR_proto_t;
|
||||
|
||||
typedef struct MIR_data {
|
||||
const char *name; /* can be NULL */
|
||||
MIR_type_t el_type;
|
||||
size_t nel;
|
||||
union {
|
||||
long double d; /* for alignment of temporary literals */
|
||||
uint8_t els[1];
|
||||
} u;
|
||||
} * MIR_data_t;
|
||||
|
||||
typedef struct MIR_ref_data {
|
||||
const char *name; /* can be NULL */
|
||||
MIR_item_t ref_item; /* base */
|
||||
int64_t disp; /* disp relative to base */
|
||||
void *load_addr;
|
||||
} * MIR_ref_data_t;
|
||||
|
||||
typedef struct MIR_expr_data {
|
||||
const char *name; /* can be NULL */
|
||||
MIR_item_t expr_item; /* a special function can be called during linking */
|
||||
void *load_addr;
|
||||
} * MIR_expr_data_t;
|
||||
|
||||
typedef struct MIR_bss {
|
||||
const char *name; /* can be NULL */
|
||||
uint64_t len;
|
||||
} * MIR_bss_t;
|
||||
|
||||
typedef struct MIR_module *MIR_module_t;
|
||||
|
||||
/* Definition of link of double list of MIR_item_t type elements */
|
||||
DEF_DLIST_LINK (MIR_item_t);
|
||||
|
||||
#define ITEM_EL(i) MIR_##i##_item
|
||||
|
||||
typedef enum {
|
||||
REP8 (ITEM_EL, func, proto, import, export, forward, data, ref_data, expr_data),
|
||||
ITEM_EL (bss),
|
||||
} MIR_item_type_t;
|
||||
|
||||
#undef ERR_EL
|
||||
#undef INSN_EL
|
||||
#undef TYPE_EL
|
||||
#undef OP_EL
|
||||
#undef ITEM_EL
|
||||
#undef REP_SEP
|
||||
|
||||
/* MIR module items (function or import): */
|
||||
struct MIR_item {
|
||||
void *data;
|
||||
MIR_module_t module;
|
||||
DLIST_LINK (MIR_item_t) item_link;
|
||||
MIR_item_type_t item_type; /* item type */
|
||||
/* Non-null only for export/forward items and import item after
|
||||
linking. It forms a chain to the final definition. */
|
||||
MIR_item_t ref_def;
|
||||
/* address of loaded data/bss items, function to call the function
|
||||
item, imported definition or proto object */
|
||||
void *addr;
|
||||
char export_p; /* true for export items (only func items) */
|
||||
union {
|
||||
MIR_func_t func;
|
||||
MIR_proto_t proto;
|
||||
MIR_name_t import;
|
||||
MIR_name_t export;
|
||||
MIR_name_t forward;
|
||||
MIR_data_t data;
|
||||
MIR_ref_data_t ref_data;
|
||||
MIR_expr_data_t expr_data;
|
||||
MIR_bss_t bss;
|
||||
} u;
|
||||
};
|
||||
|
||||
/* Definition of double list of MIR_item_t type elements */
|
||||
DEF_DLIST (MIR_item_t, item_link);
|
||||
|
||||
/* Definition of link of double list of MIR_module_t type elements */
|
||||
DEF_DLIST_LINK (MIR_module_t);
|
||||
|
||||
/* MIR module: */
|
||||
struct MIR_module {
|
||||
void *data;
|
||||
const char *name;
|
||||
DLIST (MIR_item_t) items; /* module items */
|
||||
DLIST_LINK (MIR_module_t) module_link;
|
||||
uint32_t last_temp_item_num; /* Used only internally */
|
||||
};
|
||||
|
||||
/* Definition of double list of MIR_item_t type elements */
|
||||
DEF_DLIST (MIR_module_t, module_link);
|
||||
|
||||
struct MIR_context;
|
||||
typedef struct MIR_context *MIR_context_t;
|
||||
|
||||
static inline int MIR_FP_branch_code_p (MIR_insn_code_t code) {
|
||||
return (code == MIR_FBEQ || code == MIR_DBEQ || code == MIR_LDBEQ || code == MIR_FBNE
|
||||
|| code == MIR_DBNE || code == MIR_LDBNE || code == MIR_FBLT || code == MIR_DBLT
|
||||
|| code == MIR_LDBLT || code == MIR_FBLE || code == MIR_DBLE || code == MIR_LDBLE
|
||||
|| code == MIR_FBGT || code == MIR_DBGT || code == MIR_LDBGT || code == MIR_FBGE
|
||||
|| code == MIR_DBGE || code == MIR_LDBGE);
|
||||
}
|
||||
|
||||
static inline int MIR_call_code_p (MIR_insn_code_t code) {
|
||||
return code == MIR_CALL || code == MIR_INLINE;
|
||||
}
|
||||
|
||||
static inline int MIR_int_branch_code_p (MIR_insn_code_t code) {
|
||||
return (code == MIR_BT || code == MIR_BTS || code == MIR_BF || code == MIR_BFS || code == MIR_BEQ
|
||||
|| code == MIR_BEQS || code == MIR_BNE || code == MIR_BNES || code == MIR_BLT
|
||||
|| code == MIR_BLTS || code == MIR_UBLT || code == MIR_UBLTS || code == MIR_BLE
|
||||
|| code == MIR_BLES || code == MIR_UBLE || code == MIR_UBLES || code == MIR_BGT
|
||||
|| code == MIR_BGTS || code == MIR_UBGT || code == MIR_UBGTS || code == MIR_BGE
|
||||
|| code == MIR_BGES || code == MIR_UBGE || code == MIR_UBGES);
|
||||
}
|
||||
|
||||
static inline int MIR_branch_code_p (MIR_insn_code_t code) {
|
||||
return (code == MIR_JMP || MIR_int_branch_code_p (code) || MIR_FP_branch_code_p (code));
|
||||
}
|
||||
|
||||
/* Use only the following API to create MIR code. */
|
||||
extern MIR_context_t MIR_init (void);
|
||||
extern void MIR_finish (MIR_context_t ctx);
|
||||
|
||||
extern MIR_module_t MIR_new_module (MIR_context_t ctx, const char *name);
|
||||
extern DLIST (MIR_module_t) * MIR_get_module_list (MIR_context_t ctx);
|
||||
extern MIR_item_t MIR_new_import (MIR_context_t ctx, const char *name);
|
||||
extern MIR_item_t MIR_new_export (MIR_context_t ctx, const char *name);
|
||||
extern MIR_item_t MIR_new_forward (MIR_context_t ctx, const char *name);
|
||||
extern MIR_item_t MIR_new_bss (MIR_context_t ctx, const char *name,
|
||||
size_t len); /* name can be NULL */
|
||||
extern MIR_item_t MIR_new_data (MIR_context_t ctx, const char *name, MIR_type_t el_type, size_t nel,
|
||||
const void *els); /* name can be NULL */
|
||||
extern MIR_item_t MIR_new_string_data (MIR_context_t ctx, const char *name,
|
||||
MIR_str_t str); /* name can be NULL */
|
||||
extern MIR_item_t MIR_new_ref_data (MIR_context_t ctx, const char *name, MIR_item_t item,
|
||||
int64_t disp); /* name can be NULL */
|
||||
extern MIR_item_t MIR_new_expr_data (MIR_context_t ctx, const char *name,
|
||||
MIR_item_t expr_item); /* name can be NULL */
|
||||
extern MIR_item_t MIR_new_proto_arr (MIR_context_t ctx, const char *name, size_t nres,
|
||||
MIR_type_t *res_types, size_t nargs, MIR_var_t *vars);
|
||||
extern MIR_item_t MIR_new_proto (MIR_context_t ctx, const char *name, size_t nres,
|
||||
MIR_type_t *res_types, size_t nargs, ...);
|
||||
extern MIR_item_t MIR_new_vararg_proto_arr (MIR_context_t ctx, const char *name, size_t nres,
|
||||
MIR_type_t *res_types, size_t nargs, MIR_var_t *vars);
|
||||
extern MIR_item_t MIR_new_vararg_proto (MIR_context_t ctx, const char *name, size_t nres,
|
||||
MIR_type_t *res_types, size_t nargs, ...);
|
||||
extern MIR_item_t MIR_new_func_arr (MIR_context_t ctx, const char *name, size_t nres,
|
||||
MIR_type_t *res_types, size_t nargs, MIR_var_t *vars);
|
||||
extern MIR_item_t MIR_new_func (MIR_context_t ctx, const char *name, size_t nres,
|
||||
MIR_type_t *res_types, size_t nargs, ...);
|
||||
extern MIR_item_t MIR_new_vararg_func_arr (MIR_context_t ctx, const char *name, size_t nres,
|
||||
MIR_type_t *res_types, size_t nargs, MIR_var_t *vars);
|
||||
extern MIR_item_t MIR_new_vararg_func (MIR_context_t ctx, const char *name, size_t nres,
|
||||
MIR_type_t *res_types, size_t nargs, ...);
|
||||
extern const char *MIR_item_name (MIR_context_t ctx, MIR_item_t item);
|
||||
extern MIR_reg_t MIR_new_func_reg (MIR_context_t ctx, MIR_func_t func, MIR_type_t type,
|
||||
const char *name);
|
||||
extern void MIR_finish_func (MIR_context_t ctx);
|
||||
extern void MIR_finish_module (MIR_context_t ctx);
|
||||
|
||||
extern MIR_error_func_t MIR_get_error_func (MIR_context_t ctx);
|
||||
extern void MIR_set_error_func (MIR_context_t ctx, MIR_error_func_t func);
|
||||
|
||||
extern MIR_insn_t MIR_new_insn_arr (MIR_context_t ctx, MIR_insn_code_t code, size_t nops,
|
||||
MIR_op_t *ops);
|
||||
extern MIR_insn_t MIR_new_insn (MIR_context_t ctx, MIR_insn_code_t code, ...);
|
||||
extern MIR_insn_t MIR_new_call_insn (MIR_context_t ctx, size_t nops, ...);
|
||||
extern MIR_insn_t MIR_new_ret_insn (MIR_context_t ctx, size_t nops, ...);
|
||||
extern MIR_insn_t MIR_copy_insn (MIR_context_t ctx, MIR_insn_t insn);
|
||||
|
||||
extern const char *MIR_insn_name (MIR_context_t ctx, MIR_insn_code_t code);
|
||||
extern size_t MIR_insn_nops (MIR_context_t ctx, MIR_insn_t insn);
|
||||
extern MIR_op_mode_t MIR_insn_op_mode (MIR_context_t ctx, MIR_insn_t insn, size_t nop, int *out_p);
|
||||
|
||||
extern MIR_insn_t MIR_new_label (MIR_context_t ctx);
|
||||
|
||||
extern MIR_reg_t MIR_reg (MIR_context_t ctx, const char *reg_name, MIR_func_t func);
|
||||
extern MIR_type_t MIR_reg_type (MIR_context_t ctx, MIR_reg_t reg, MIR_func_t func);
|
||||
extern const char *MIR_reg_name (MIR_context_t ctx, MIR_reg_t reg, MIR_func_t func);
|
||||
|
||||
extern MIR_op_t MIR_new_reg_op (MIR_context_t ctx, MIR_reg_t reg);
|
||||
extern MIR_op_t MIR_new_int_op (MIR_context_t ctx, int64_t v);
|
||||
extern MIR_op_t MIR_new_uint_op (MIR_context_t ctx, uint64_t v);
|
||||
extern MIR_op_t MIR_new_float_op (MIR_context_t ctx, float v);
|
||||
extern MIR_op_t MIR_new_double_op (MIR_context_t ctx, double v);
|
||||
extern MIR_op_t MIR_new_ldouble_op (MIR_context_t ctx, long double v);
|
||||
extern MIR_op_t MIR_new_ref_op (MIR_context_t ctx, MIR_item_t item);
|
||||
extern MIR_op_t MIR_new_str_op (MIR_context_t ctx, MIR_str_t str);
|
||||
extern MIR_op_t MIR_new_mem_op (MIR_context_t ctx, MIR_type_t type, MIR_disp_t disp, MIR_reg_t base,
|
||||
MIR_reg_t index, MIR_scale_t scale);
|
||||
extern MIR_op_t MIR_new_label_op (MIR_context_t ctx, MIR_label_t label);
|
||||
extern int MIR_op_eq_p (MIR_context_t ctx, MIR_op_t op1, MIR_op_t op2);
|
||||
extern htab_hash_t MIR_op_hash_step (MIR_context_t ctx, htab_hash_t h, MIR_op_t op);
|
||||
|
||||
extern void MIR_append_insn (MIR_context_t ctx, MIR_item_t func, MIR_insn_t insn);
|
||||
extern void MIR_prepend_insn (MIR_context_t ctx, MIR_item_t func, MIR_insn_t insn);
|
||||
extern void MIR_insert_insn_after (MIR_context_t ctx, MIR_item_t func, MIR_insn_t after,
|
||||
MIR_insn_t insn);
|
||||
extern void MIR_insert_insn_before (MIR_context_t ctx, MIR_item_t func, MIR_insn_t before,
|
||||
MIR_insn_t insn);
|
||||
extern void MIR_remove_insn (MIR_context_t ctx, MIR_item_t func, MIR_insn_t insn);
|
||||
|
||||
extern const char *MIR_type_str (MIR_context_t ctx, MIR_type_t tp);
|
||||
extern void MIR_output_op (MIR_context_t ctx, FILE *f, MIR_op_t op, MIR_func_t func);
|
||||
extern void MIR_output_insn (MIR_context_t ctx, FILE *f, MIR_insn_t insn, MIR_func_t func,
|
||||
int newline_p);
|
||||
extern void MIR_output_item (MIR_context_t ctx, FILE *f, MIR_item_t item);
|
||||
extern void MIR_output_module (MIR_context_t ctx, FILE *f, MIR_module_t module);
|
||||
extern void MIR_output (MIR_context_t ctx, FILE *f);
|
||||
|
||||
#if !MIR_NO_IO
|
||||
extern void MIR_write (MIR_context_t ctx, FILE *f);
|
||||
extern void MIR_write_module (MIR_context_t ctx, FILE *f, MIR_module_t module);
|
||||
extern void MIR_read (MIR_context_t ctx, FILE *f);
|
||||
extern void MIR_write_with_func (MIR_context_t ctx,
|
||||
const int (*writer_func) (MIR_context_t, uint8_t));
|
||||
extern void MIR_write_module_with_func (MIR_context_t ctx,
|
||||
const int (*writer_func) (MIR_context_t, uint8_t),
|
||||
MIR_module_t module);
|
||||
extern void MIR_read_with_func (MIR_context_t ctx, const int (*reader_func) (MIR_context_t));
|
||||
#endif
|
||||
|
||||
#if !MIR_NO_SCAN
|
||||
extern void MIR_scan_string (MIR_context_t ctx, const char *str);
|
||||
#endif
|
||||
|
||||
extern MIR_item_t MIR_get_global_item (MIR_context_t ctx, const char *name);
|
||||
extern void MIR_load_module (MIR_context_t ctx, MIR_module_t m);
|
||||
extern void MIR_load_external (MIR_context_t ctx, const char *name, void *addr);
|
||||
extern void MIR_link (MIR_context_t ctx, void (*set_interface) (MIR_context_t ctx, MIR_item_t item),
|
||||
void *(*import_resolver) (const char *) );
|
||||
|
||||
/* Interpreter: */
|
||||
typedef union {
|
||||
MIR_insn_code_t ic;
|
||||
void *a;
|
||||
int64_t i;
|
||||
uint64_t u;
|
||||
float f;
|
||||
double d;
|
||||
long double ld;
|
||||
} MIR_val_t;
|
||||
|
||||
extern void MIR_interp (MIR_context_t ctx, MIR_item_t func_item, MIR_val_t *results, size_t nargs,
|
||||
...);
|
||||
extern void MIR_interp_arr (MIR_context_t ctx, MIR_item_t func_item, MIR_val_t *results,
|
||||
size_t nargs, MIR_val_t *vals);
|
||||
extern void MIR_interp_arr_varg (MIR_context_t ctx, MIR_item_t func_item, MIR_val_t *results,
|
||||
size_t nargs, MIR_val_t *vals, va_list va);
|
||||
extern void MIR_set_interp_interface (MIR_context_t ctx, MIR_item_t func_item);
|
||||
|
||||
/* Private: */
|
||||
extern const char *_MIR_uniq_string (MIR_context_t ctx, const char *str);
|
||||
extern int _MIR_reserved_ref_name_p (MIR_context_t ctx, const char *name);
|
||||
extern int _MIR_reserved_name_p (MIR_context_t ctx, const char *name);
|
||||
extern MIR_reg_t _MIR_new_temp_reg (MIR_context_t ctx, MIR_type_t type,
|
||||
MIR_func_t func); /* for internal use only */
|
||||
extern size_t _MIR_type_size (MIR_context_t ctx, MIR_type_t type);
|
||||
extern MIR_op_mode_t _MIR_insn_code_op_mode (MIR_context_t ctx, MIR_insn_code_t code, size_t nop,
|
||||
int *out_p);
|
||||
extern void _MIR_duplicate_func_insns (MIR_context_t ctx, MIR_item_t func_item);
|
||||
extern void _MIR_restore_func_insns (MIR_context_t ctx, MIR_item_t func_item);
|
||||
extern void _MIR_simplify_insn (MIR_context_t ctx, MIR_item_t func_item, MIR_insn_t insn,
|
||||
int keep_ref_p, int mem_float_p);
|
||||
|
||||
extern const char *_MIR_get_temp_item_name (MIR_context_t ctx, MIR_module_t module);
|
||||
|
||||
extern MIR_op_t _MIR_new_hard_reg_op (MIR_context_t ctx, MIR_reg_t hard_reg);
|
||||
|
||||
extern MIR_op_t _MIR_new_hard_reg_mem_op (MIR_context_t ctx, MIR_type_t type, MIR_disp_t disp,
|
||||
MIR_reg_t base, MIR_reg_t index, MIR_scale_t scale);
|
||||
|
||||
extern MIR_item_t _MIR_builtin_proto (MIR_context_t ctx, MIR_module_t module, const char *name,
|
||||
size_t nres, MIR_type_t *res_types, size_t nargs, ...);
|
||||
extern MIR_item_t _MIR_builtin_func (MIR_context_t ctx, MIR_module_t module, const char *name,
|
||||
void *addr);
|
||||
|
||||
extern uint8_t *_MIR_publish_code (MIR_context_t ctx, const uint8_t *code, size_t code_len);
|
||||
|
||||
struct MIR_code_reloc {
|
||||
size_t offset;
|
||||
void *value;
|
||||
};
|
||||
|
||||
typedef struct MIR_code_reloc MIR_code_reloc_t;
|
||||
|
||||
extern void _MIR_update_code_arr (MIR_context_t ctx, uint8_t *base, size_t nloc,
|
||||
const MIR_code_reloc_t *relocs);
|
||||
extern void _MIR_update_code (MIR_context_t ctx, uint8_t *base, size_t nloc, ...);
|
||||
|
||||
extern void *va_arg_builtin (void *p, uint64_t t);
|
||||
extern void va_start_interp_builtin (MIR_context_t ctx, void *p, void *a);
|
||||
extern void va_end_interp_builtin (MIR_context_t ctx, void *p);
|
||||
|
||||
extern void *_MIR_get_bstart_builtin (MIR_context_t ctx);
|
||||
extern void *_MIR_get_bend_builtin (MIR_context_t ctx);
|
||||
|
||||
extern void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, size_t nargs,
|
||||
MIR_type_t *arg_types);
|
||||
extern void *_MIR_get_interp_shim (MIR_context_t ctx, MIR_item_t func_item, void *handler);
|
||||
extern void *_MIR_get_thunk (MIR_context_t ctx);
|
||||
extern void _MIR_redirect_thunk (MIR_context_t ctx, void *thunk, void *to);
|
||||
extern void *_MIR_get_wrapper (MIR_context_t ctx, MIR_item_t called_func, void *hook_address);
|
||||
|
||||
#endif /* #ifndef MIR_H */
|
Loading…
Reference in new issue