Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • hammer/hammer
  • mlp/hammer
  • xentrac/hammer
  • pesco/hammer
  • letitiali/hammer
  • nobody/hammer
  • kia/hammer-sandbox
  • vyrus001/hammer
  • denleylam/hammer
9 results
Show changes
Commits on Source (27)
...@@ -23,3 +23,4 @@ build/ ...@@ -23,3 +23,4 @@ build/
.sconsign.dblite .sconsign.dblite
*.os *.os
*.pyc *.pyc
*.ll
\ No newline at end of file
...@@ -41,7 +41,7 @@ if 'DESTDIR' in env: ...@@ -41,7 +41,7 @@ if 'DESTDIR' in env:
print >>sys.stderr, "--!!-- you want; files will be installed in" print >>sys.stderr, "--!!-- you want; files will be installed in"
print >>sys.stderr, "--!!-- %s" % (calcInstallPath("$prefix"),) print >>sys.stderr, "--!!-- %s" % (calcInstallPath("$prefix"),)
env['LLVM_CONFIG'] = "llvm-config"
env['libpath'] = calcInstallPath("$prefix", "lib") env['libpath'] = calcInstallPath("$prefix", "lib")
env['incpath'] = calcInstallPath("$prefix", "include", "hammer") env['incpath'] = calcInstallPath("$prefix", "include", "hammer")
env['parsersincpath'] = calcInstallPath("$prefix", "include", "hammer", "parsers") env['parsersincpath'] = calcInstallPath("$prefix", "include", "hammer", "parsers")
...@@ -49,7 +49,7 @@ env['backendsincpath'] = calcInstallPath("$prefix", "include", "hammer", "backen ...@@ -49,7 +49,7 @@ env['backendsincpath'] = calcInstallPath("$prefix", "include", "hammer", "backen
env['pkgconfigpath'] = calcInstallPath("$prefix", "lib", "pkgconfig") env['pkgconfigpath'] = calcInstallPath("$prefix", "lib", "pkgconfig")
env.ScanReplace('libhammer.pc.in') env.ScanReplace('libhammer.pc.in')
env.MergeFlags("-std=gnu99 -Wall -Wextra -Werror -Wno-unused-parameter -Wno-attributes -Wno-unused-variable") env.MergeFlags("-std=gnu11 -Wno-unused-parameter -Wno-attributes -Wno-unused-variable -Wall -Wextra -Werror")
if env['PLATFORM'] == 'darwin': if env['PLATFORM'] == 'darwin':
env.Append(SHLINKFLAGS = '-install_name ' + env["libpath"] + '/${TARGET.file}') env.Append(SHLINKFLAGS = '-install_name ' + env["libpath"] + '/${TARGET.file}')
...@@ -80,7 +80,7 @@ AddOption("--in-place", ...@@ -80,7 +80,7 @@ AddOption("--in-place",
dbg = env.Clone(VARIANT='debug') dbg = env.Clone(VARIANT='debug')
dbg.Append(CCFLAGS=['-g']) dbg.MergeFlags("-g -O0")
opt = env.Clone(VARIANT='opt') opt = env.Clone(VARIANT='opt')
opt.Append(CCFLAGS=["-O3"]) opt.Append(CCFLAGS=["-O3"])
...@@ -92,6 +92,7 @@ else: ...@@ -92,6 +92,7 @@ else:
env["CC"] = os.getenv("CC") or env["CC"] env["CC"] = os.getenv("CC") or env["CC"]
env["CXX"] = os.getenv("CXX") or env["CXX"] env["CXX"] = os.getenv("CXX") or env["CXX"]
env["LLVM_CONFIG"] = os.getenv("LLVM_CONFIG") or env["LLVM_CONFIG"]
if GetOption("coverage"): if GetOption("coverage"):
env.Append(CFLAGS=["--coverage"], env.Append(CFLAGS=["--coverage"],
...@@ -100,7 +101,8 @@ if GetOption("coverage"): ...@@ -100,7 +101,8 @@ if GetOption("coverage"):
if env["CC"] == "gcc": if env["CC"] == "gcc":
env.Append(LIBS=['gcov']) env.Append(LIBS=['gcov'])
else: else:
env.ParseConfig('llvm-config --ldflags') env.ParseConfig('%s --cflags --ldflags --libs core executionengine mcjit analysis x86codegen x86info' % \
env["LLVM_CONFIG"])
if os.getenv("CC") == "clang" or env['PLATFORM'] == 'darwin': if os.getenv("CC") == "clang" or env['PLATFORM'] == 'darwin':
env.Replace(CC="clang", env.Replace(CC="clang",
......
# -*- python -*- # -*- python -*-
import os.path import os.path
from distutils.version import LooseVersion
import re
import subprocess
Import('env testruns') Import('env testruns')
dist_headers = [ dist_headers = [
...@@ -51,7 +55,7 @@ parsers = ['parsers/%s.c'%s for s in ...@@ -51,7 +55,7 @@ parsers = ['parsers/%s.c'%s for s in
'value']] 'value']]
backends = ['backends/%s.c' % s for s in backends = ['backends/%s.c' % s for s in
['packrat', 'llk', 'regex', 'glr', 'lalr', 'lr', 'lr0']] ['packrat', 'llk', 'regex', 'glr', 'lalr', 'lr', 'lr0', 'llvm']]
misc_hammer_parts = [ misc_hammer_parts = [
'allocator.c', 'allocator.c',
...@@ -76,6 +80,20 @@ ctests = ['t_benchmark.c', ...@@ -76,6 +80,20 @@ ctests = ['t_benchmark.c',
't_misc.c', 't_misc.c',
't_regression.c'] 't_regression.c']
# llvm-config 'helpfully' supplies -g and -O flags; educate it with this
# custom ParseConfig function arg
def llvm_config_sanitize(env, cmd, unique=1):
# cmd is output from llvm-config
flags = cmd.split()
# match -g or -O flags
p = re.compile("^-[gO].*$")
filtered_flags = [flag for flag in flags if not p.match(flag)]
filtered_cmd = ' '.join(filtered_flags)
# print "llvm_config_sanitize: \"%s\" => \"%s\"" % (cmd, filtered_cmd)
env.MergeFlags(filtered_cmd, unique)
env.ParseConfig('%s --cflags --ldflags' % env["LLVM_CONFIG"], function=llvm_config_sanitize)
libhammer_shared = env.SharedLibrary('hammer', parsers + backends + misc_hammer_parts) libhammer_shared = env.SharedLibrary('hammer', parsers + backends + misc_hammer_parts)
libhammer_static = env.StaticLibrary('hammer', parsers + backends + misc_hammer_parts) libhammer_static = env.StaticLibrary('hammer', parsers + backends + misc_hammer_parts)
Default(libhammer_shared, libhammer_static) Default(libhammer_shared, libhammer_static)
...@@ -87,8 +105,20 @@ env.Install("$backendsincpath", backends_headers) ...@@ -87,8 +105,20 @@ env.Install("$backendsincpath", backends_headers)
env.Install("$pkgconfigpath", "../../../libhammer.pc") env.Install("$pkgconfigpath", "../../../libhammer.pc")
testenv = env.Clone() testenv = env.Clone()
testenv.ParseConfig('pkg-config --cflags --libs glib-2.0')
testenv.Append(LIBS=['hammer'], LIBPATH=['.']) testenv.Append(LIBS=['hammer'], LIBPATH=['.'])
testenv.ParseConfig('pkg-config --cflags --libs glib-2.0')
testenv_llvm_config_version = subprocess.Popen('%s --version' % env["LLVM_CONFIG"], \
shell=True, \
stdin=subprocess.PIPE, stdout=subprocess.PIPE).communicate()
if LooseVersion(testenv_llvm_config_version[0]) < LooseVersion("3.9") and \
LooseVersion(testenv_llvm_config_version[0]) >= LooseVersion("3.5"):
testenv_llvm_system_libs_flag = "--system-libs"
else:
testenv_llvm_system_libs_flag = ""
testenv.ParseConfig('%s --cflags --ldflags --libs %s core executionengine mcjit analysis x86codegen x86info' % \
(env["LLVM_CONFIG"], testenv_llvm_system_libs_flag), function=llvm_config_sanitize)
testenv.Append(LIBS=['stdc++'], LIBPATH=['.'])
ctestexec = testenv.Program('test_suite', ctests + ['test_suite.c'], LINKFLAGS="--coverage" if testenv.GetOption("coverage") else None) ctestexec = testenv.Program('test_suite', ctests + ['test_suite.c'], LINKFLAGS="--coverage" if testenv.GetOption("coverage") else None)
ctest = Alias('testc', [ctestexec], "".join(["env LD_LIBRARY_PATH=", os.path.dirname(ctestexec[0].path), " ", ctestexec[0].path])) ctest = Alias('testc', [ctestexec], "".join(["env LD_LIBRARY_PATH=", os.path.dirname(ctestexec[0].path), " ", ctestexec[0].path]))
AlwaysBuild(ctest) AlwaysBuild(ctest)
......
#include <llvm-c/Analysis.h>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
#include <llvm-c/Core.h>
#pragma GCC diagnostic pop
#include <llvm-c/ExecutionEngine.h>
#include "../internal.h"
#include "../llvm.h"
typedef struct HLLVMParser_ {
LLVMModuleRef mod;
LLVMValueRef func;
LLVMExecutionEngineRef engine;
LLVMBuilderRef builder;
} HLLVMParser;
HParseResult* make_result(HArena *arena, HParsedToken *tok) {
HParseResult *ret = h_arena_malloc(arena, sizeof(HParseResult));
ret->ast = tok;
ret->arena = arena;
ret->bit_length = 0; // This way it gets overridden in h_do_parse
return ret;
}
void h_llvm_declare_common(LLVMModuleRef mod) {
llvm_inputstream = LLVMStructCreateNamed(LLVMGetGlobalContext(), "struct.HInputStream_");
LLVMTypeRef llvm_inputstream_struct_types[] = {
LLVMPointerType(LLVMInt8Type(), 0),
LLVMInt64Type(),
LLVMInt64Type(),
LLVMInt64Type(),
LLVMInt8Type(),
LLVMInt8Type(),
LLVMInt8Type(),
LLVMInt8Type(),
LLVMInt8Type()
};
LLVMStructSetBody(llvm_inputstream, llvm_inputstream_struct_types, 9, 0);
llvm_inputstreamptr = LLVMPointerType(llvm_inputstream, 0);
llvm_arena = LLVMStructCreateNamed(LLVMGetGlobalContext(), "struct.HArena_");
llvm_arenaptr = LLVMPointerType(llvm_arena, 0);
llvm_parsedtoken = LLVMStructCreateNamed(LLVMGetGlobalContext(), "struct.HParsedToken_");
LLVMTypeRef llvm_parsedtoken_struct_types[] = {
LLVMInt32Type(), // actually an enum value
LLVMInt64Type(), // actually this is a union; the largest thing in it is 64 bits
LLVMInt64Type(), // FIXME sizeof(size_t) will be 32 bits on 32-bit platforms
LLVMInt64Type(), // FIXME ditto
LLVMInt8Type()
};
LLVMStructSetBody(llvm_parsedtoken, llvm_parsedtoken_struct_types, 5, 0);
llvm_parsedtokenptr = LLVMPointerType(llvm_parsedtoken, 0);
llvm_parseresult = LLVMStructCreateNamed(LLVMGetGlobalContext(), "struct.HParseResult_");
LLVMTypeRef llvm_parseresult_struct_types[] = {
llvm_parsedtokenptr,
LLVMInt64Type(),
llvm_arenaptr
};
LLVMStructSetBody(llvm_parseresult, llvm_parseresult_struct_types, 3, 0);
llvm_parseresultptr = LLVMPointerType(llvm_parseresult, 0);
LLVMTypeRef readbits_pt[] = {
llvm_inputstreamptr,
LLVMInt32Type(),
LLVMInt8Type()
};
LLVMTypeRef readbits_ret = LLVMFunctionType(LLVMInt64Type(), readbits_pt, 3, 0);
LLVMAddFunction(mod, "h_read_bits", readbits_ret);
LLVMTypeRef amalloc_pt[] = {
llvm_arenaptr,
LLVMInt32Type()
};
LLVMTypeRef amalloc_ret = LLVMFunctionType(LLVMPointerType(LLVMVoidType(), 0), amalloc_pt, 2, 0);
LLVMAddFunction(mod, "h_arena_malloc", amalloc_ret);
LLVMTypeRef makeresult_pt[] = {
llvm_arenaptr,
llvm_parsedtokenptr
};
LLVMTypeRef makeresult_ret = LLVMFunctionType(llvm_parseresultptr, makeresult_pt, 2, 0);
LLVMAddFunction(mod, "make_result", makeresult_ret);
}
int h_llvm_compile(HAllocator* mm__, HParser* parser, const void* params) {
// Boilerplate to set up a translation unit, aka a module.
const char* name = params ? (const char*)params : "parse";
LLVMModuleRef mod = LLVMModuleCreateWithName(name);
h_llvm_declare_common(mod);
// Boilerplate to set up the parser function to add to the module. It takes an HInputStream* and
// returns an HParseResult.
LLVMTypeRef param_types[] = {
llvm_inputstreamptr,
llvm_arenaptr
};
LLVMTypeRef ret_type = LLVMFunctionType(llvm_parseresultptr, param_types, 2, 0);
LLVMValueRef parse_func = LLVMAddFunction(mod, name, ret_type);
// Parse function is now declared; time to define it
LLVMBuilderRef builder = LLVMCreateBuilder();
// Translate the contents of the children of `parser` into their LLVM instruction equivalents
if (parser->vtable->llvm(builder, parse_func, mod, parser->env)) {
// But first, verification
char *error = NULL;
LLVMVerifyModule(mod, LLVMAbortProcessAction, &error);
LLVMDisposeMessage(error);
error = NULL;
// OK, link that sonofabitch
LLVMLinkInMCJIT();
LLVMInitializeNativeTarget();
LLVMInitializeNativeAsmPrinter();
LLVMExecutionEngineRef engine = NULL;
LLVMCreateExecutionEngineForModule(&engine, mod, &error);
if (error) {
fprintf(stderr, "error: %s\n", error);
LLVMDisposeMessage(error);
return -1;
}
char* dump = LLVMPrintModuleToString(mod);
fprintf(stderr, "\n\n%s\n\n", dump);
// Package up the pointers that comprise the module and stash it in the original HParser
HLLVMParser *llvm_parser = h_new(HLLVMParser, 1);
llvm_parser->mod = mod;
llvm_parser->func = parse_func;
llvm_parser->engine = engine;
llvm_parser->builder = builder;
parser->backend_data = llvm_parser;
return 0;
} else {
return -1;
}
}
void h_llvm_free(HParser *parser) {
HLLVMParser *llvm_parser = parser->backend_data;
LLVMModuleRef mod_out;
char *err_out;
llvm_parser->func = NULL;
LLVMRemoveModule(llvm_parser->engine, llvm_parser->mod, &mod_out, &err_out);
LLVMDisposeExecutionEngine(llvm_parser->engine);
llvm_parser->engine = NULL;
LLVMDisposeBuilder(llvm_parser->builder);
llvm_parser->builder = NULL;
LLVMDisposeModule(llvm_parser->mod);
llvm_parser->mod = NULL;
}
HParseResult *h_llvm_parse(HAllocator* mm__, const HParser* parser, HInputStream *input_stream) {
const HLLVMParser *llvm_parser = parser->backend_data;
HArena *arena = h_new_arena(mm__, 0);
// LLVMRunFunction only supports certain signatures for dumb reasons; it's this hack with
// memcpy and function pointers, or writing a shim in LLVM IR.
//
// LLVMGenericValueRef args[] = {
// LLVMCreateGenericValueOfPointer(input_stream),
// LLVMCreateGenericValueOfPointer(arena)
// };
// LLVMGenericValueRef res = LLVMRunFunction(llvm_parser->engine, llvm_parser->func, 2, args);
// HParseResult *ret = (HParseResult*)LLVMGenericValueToPointer(res);
void *parse_func_ptr_v;
HParseResult * (*parse_func_ptr)(HInputStream *input_stream, HArena *arena);
parse_func_ptr_v = LLVMGetPointerToGlobal(llvm_parser->engine, llvm_parser->func);
memcpy(&parse_func_ptr, &parse_func_ptr_v, sizeof(parse_func_ptr));
HParseResult *ret = parse_func_ptr(input_stream, arena);
if (ret) {
ret->arena = arena;
if (!input_stream->overrun) {
size_t bit_length = h_input_stream_pos(input_stream);
if (ret->bit_length == 0) {
ret->bit_length = bit_length;
}
if (ret->ast && ret->ast->bit_length != 0) {
((HParsedToken*)(ret->ast))->bit_length = bit_length;
}
} else {
ret->bit_length = 0;
}
} else {
ret = NULL;
}
if (input_stream->overrun) {
return NULL; // overrun is always failure.
}
return ret;
}
HParserBackendVTable h__llvm_backend_vtable = {
.compile = h_llvm_compile,
.parse = h_llvm_parse,
.free = h_llvm_free
};
#ifndef _GNU_SOURCE
#define _GNU_SOURCE #define _GNU_SOURCE
#endif
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#include "../internal.h" #include "../internal.h"
......
...@@ -31,6 +31,7 @@ static HParserBackendVTable *backends[PB_MAX + 1] = { ...@@ -31,6 +31,7 @@ static HParserBackendVTable *backends[PB_MAX + 1] = {
&h__llk_backend_vtable, &h__llk_backend_vtable,
&h__lalr_backend_vtable, &h__lalr_backend_vtable,
&h__glr_backend_vtable, &h__glr_backend_vtable,
&h__llvm_backend_vtable,
}; };
......
...@@ -46,7 +46,8 @@ typedef enum HParserBackend_ { ...@@ -46,7 +46,8 @@ typedef enum HParserBackend_ {
PB_LLk, PB_LLk,
PB_LALR, PB_LALR,
PB_GLR, PB_GLR,
PB_MAX = PB_GLR PB_LLVM,
PB_MAX = PB_LLVM
} HParserBackend; } HParserBackend;
typedef enum HTokenType_ { typedef enum HTokenType_ {
...@@ -177,7 +178,7 @@ typedef HParser* (*HContinuation)(HAllocator *mm__, const HParsedToken *x, void ...@@ -177,7 +178,7 @@ typedef HParser* (*HContinuation)(HAllocator *mm__, const HParsedToken *x, void
typedef struct HParserTestcase_ { typedef struct HParserTestcase_ {
unsigned char* input; unsigned char* input;
size_t length; size_t length;
char* output_unambiguous; const char* output_unambiguous;
} HParserTestcase; } HParserTestcase;
#ifdef SWIG #ifdef SWIG
......
...@@ -25,6 +25,10 @@ ...@@ -25,6 +25,10 @@
#include <stdint.h> #include <stdint.h>
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
#include <llvm-c/Core.h>
#pragma GCC diagnostic pop
#include "hammer.h" #include "hammer.h"
#include "platform.h" #include "platform.h"
...@@ -322,6 +326,7 @@ extern HParserBackendVTable h__packrat_backend_vtable; ...@@ -322,6 +326,7 @@ extern HParserBackendVTable h__packrat_backend_vtable;
extern HParserBackendVTable h__llk_backend_vtable; extern HParserBackendVTable h__llk_backend_vtable;
extern HParserBackendVTable h__lalr_backend_vtable; extern HParserBackendVTable h__lalr_backend_vtable;
extern HParserBackendVTable h__glr_backend_vtable; extern HParserBackendVTable h__glr_backend_vtable;
extern HParserBackendVTable h__llvm_backend_vtable;
// }}} // }}}
// TODO(thequux): Set symbol visibility for these functions so that they aren't exported. // TODO(thequux): Set symbol visibility for these functions so that they aren't exported.
...@@ -419,6 +424,7 @@ struct HParserVtable_ { ...@@ -419,6 +424,7 @@ struct HParserVtable_ {
bool (*isValidCF)(void *env); bool (*isValidCF)(void *env);
bool (*compile_to_rvm)(HRVMProg *prog, void* env); // FIXME: forgot what the bool return value was supposed to mean. bool (*compile_to_rvm)(HRVMProg *prog, void* env); // FIXME: forgot what the bool return value was supposed to mean.
void (*desugar)(HAllocator *mm__, HCFStack *stk__, void *env); void (*desugar)(HAllocator *mm__, HCFStack *stk__, void *env);
bool (*llvm)(LLVMBuilderRef builder, LLVMValueRef func, LLVMModuleRef mod, void *env);
bool higher; // false if primitive bool higher; // false if primitive
}; };
......
#ifndef HAMMER_LLVM__H
#define HAMMER_LLVM__H
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
#include <llvm-c/Core.h>
#pragma GCC diagnostic pop
LLVMTypeRef llvm_inputstream, llvm_inputstreamptr, llvm_arena, llvm_arenaptr;
LLVMTypeRef llvm_parsedtoken, llvm_parsedtokenptr, llvm_parseresult, llvm_parseresultptr;
#endif // #ifndef HAMMER_LLVM__H
...@@ -21,7 +21,10 @@ static void *aa_alloc(HAllocator *allocator, size_t size) ...@@ -21,7 +21,10 @@ static void *aa_alloc(HAllocator *allocator, size_t size)
static void *aa_realloc(HAllocator *allocator, void *ptr, size_t size) static void *aa_realloc(HAllocator *allocator, void *ptr, size_t size)
{ {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-variable"
HArena *arena = ((ArenaAllocator *)allocator)->arena; HArena *arena = ((ArenaAllocator *)allocator)->arena;
#pragma GCC diagnostic pop
assert(((void)"XXX need realloc for arena allocator", 0)); assert(((void)"XXX need realloc for arena allocator", 0));
return NULL; return NULL;
} }
......
#include <assert.h> #include <assert.h>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
#include <llvm-c/Core.h>
#pragma GCC diagnostic pop
#include "parser_internal.h" #include "parser_internal.h"
#include "../llvm.h"
struct bits_env { struct bits_env {
uint8_t length; uint8_t length;
...@@ -17,6 +22,76 @@ static HParseResult* parse_bits(void* env, HParseState *state) { ...@@ -17,6 +22,76 @@ static HParseResult* parse_bits(void* env, HParseState *state) {
return make_result(state->arena, result); return make_result(state->arena, result);
} }
static bool bits_llvm(LLVMBuilderRef builder, LLVMValueRef func, LLVMModuleRef mod, void* env) {
/* %result = alloca %struct.HParsedToken_*, align 8 */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-variable"
LLVMValueRef result = LLVMBuildAlloca(builder, llvm_parsedtoken, "result");
#pragma GCC diagnostic pop
/* store i8* %env, i8** %1, align 8 */
/* store %struct.HParseState_* %state, %struct.HParseState_** %2, align 8 */
/* %3 = load i8** %1, align 8 */
/* %4 = bitcast i8* %3 to %struct.bits_env* */
/* store %struct.bits_env* %4, %struct.bits_env** %env, align 8 */
/* %5 = load %struct.HParseState_** %2, align 8 */
/* %6 = getelementptr inbounds %struct.HParseState_* %5, i32 0, i32 2 */
/* %7 = load %struct.HArena_** %6, align 8 */
/* %8 = call noalias i8* @h_arena_malloc(%struct.HArena_* %7, i64 48) */
/* %9 = bitcast i8* %8 to %struct.HParsedToken_* */
/* store %struct.HParsedToken_* %9, %struct.HParsedToken_** %result, align 8 */
/* %10 = load %struct.bits_env** %env_, align 8 */
/* %11 = getelementptr inbounds %struct.bits_env* %10, i32 0, i32 1 */
/* %12 = load i8* %11, align 1 */
/* %13 = zext i8 %12 to i32 */
/* %14 = icmp ne i32 %13, 0 */
/* %15 = select i1 %14, i32 4, i32 8 */
/* %16 = load %struct.HParsedToken_** %result, align 8 */
/* %17 = getelementptr inbounds %struct.HParsedToken_* %16, i32 0, i32 0 */
/* store i32 %15, i32* %17, align 4 */
/* %18 = load %struct.bits_env** %env_, align 8 */
/* %19 = getelementptr inbounds %struct.bits_env* %18, i32 0, i32 1 */
/* %20 = load i8* %19, align 1 */
/* %21 = icmp ne i8 %20, 0 */
/* br i1 %21, label %22, label %33 */
/* ; <label>:22 ; preds = %0 */
/* %23 = load %struct.HParseState_** %2, align 8 */
/* %24 = getelementptr inbounds %struct.HParseState_* %23, i32 0, i32 1 */
/* %25 = load %struct.bits_env** %env_, align 8 */
/* %26 = getelementptr inbounds %struct.bits_env* %25, i32 0, i32 0 */
/* %27 = load i8* %26, align 1 */
/* %28 = zext i8 %27 to i32 */
/* %29 = call i64 @h_read_bits(%struct.HInputStream_* %24, i32 %28, i8 signext 1) */
/* %30 = load %struct.HParsedToken_** %result, align 8 */
/* %31 = getelementptr inbounds %struct.HParsedToken_* %30, i32 0, i32 1 */
/* %32 = bitcast %union.anon* %31 to i64* */
/* store i64 %29, i64* %32, align 8 */
/* br label %44 */
/* ; <label>:33 ; preds = %0 */
/* %34 = load %struct.HParseState_** %2, align 8 */
/* %35 = getelementptr inbounds %struct.HParseState_* %34, i32 0, i32 1 */
/* %36 = load %struct.bits_env** %env_, align 8 */
/* %37 = getelementptr inbounds %struct.bits_env* %36, i32 0, i32 0 */
/* %38 = load i8* %37, align 1 */
/* %39 = zext i8 %38 to i32 */
/* %40 = call i64 @h_read_bits(%struct.HInputStream_* %35, i32 %39, i8 signext 0) */
/* %41 = load %struct.HParsedToken_** %result, align 8 */
/* %42 = getelementptr inbounds %struct.HParsedToken_* %41, i32 0, i32 1 */
/* %43 = bitcast %union.anon* %42 to i64* */
/* store i64 %40, i64* %43, align 8 */
/* br label %44 */
/* ; <label>:44 ; preds = %33, %22 */
/* %45 = load %struct.HParseState_** %2, align 8 */
/* %46 = getelementptr inbounds %struct.HParseState_* %45, i32 0, i32 2 */
/* %47 = load %struct.HArena_** %46, align 8 */
/* %48 = load %struct.HParsedToken_** %result, align 8 */
/* %49 = call %struct.HParseResult_* @make_result(%struct.HArena_* %47, %struct.HParsedToken_* %48) */
/* ret %struct.HParseResult_* %49 */
return true;
}
static HParsedToken *reshape_bits(const HParseResult *p, void* signedp_p) { static HParsedToken *reshape_bits(const HParseResult *p, void* signedp_p) {
// signedp == NULL iff unsigned // signedp == NULL iff unsigned
bool signedp = (signedp_p != NULL); bool signedp = (signedp_p != NULL);
...@@ -102,6 +177,7 @@ static const HParserVtable bits_vt = { ...@@ -102,6 +177,7 @@ static const HParserVtable bits_vt = {
.isValidCF = h_true, .isValidCF = h_true,
.desugar = desugar_bits, .desugar = desugar_bits,
.compile_to_rvm = bits_ctrvm, .compile_to_rvm = bits_ctrvm,
.llvm = bits_llvm,
.higher = false, .higher = false,
}; };
......
#include <stdint.h> #include <stdint.h>
#include <assert.h> #include <assert.h>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
#include <llvm-c/Core.h>
#pragma GCC diagnostic pop
#include "parser_internal.h" #include "parser_internal.h"
#include "../llvm.h"
static HParseResult* parse_ch(void* env, HParseState *state) { static HParseResult* parse_ch(void* env, HParseState *state) {
uint8_t c = (uint8_t)(uintptr_t)(env); uint8_t c = (uint8_t)(uintptr_t)(env);
...@@ -41,12 +46,110 @@ static bool ch_ctrvm(HRVMProg *prog, void* env) { ...@@ -41,12 +46,110 @@ static bool ch_ctrvm(HRVMProg *prog, void* env) {
return true; return true;
} }
static bool ch_llvm(LLVMBuilderRef builder, LLVMValueRef func, LLVMModuleRef mod, void* env) {
// Build a new LLVM function to parse a character
// Set up params for calls to h_read_bits() and h_arena_malloc()
LLVMValueRef bits_args[3];
LLVMValueRef stream = LLVMGetFirstParam(func);
stream = LLVMBuildBitCast(builder, stream, llvm_inputstreamptr, "stream");
bits_args[0] = stream;
bits_args[1] = LLVMConstInt(LLVMInt32Type(), 8, 0);
bits_args[2] = LLVMConstInt(LLVMInt8Type(), 0, 0);
LLVMValueRef arena = LLVMGetLastParam(func);
// Set up basic blocks: entry, success and failure branches, then exit
LLVMBasicBlockRef entry = LLVMAppendBasicBlock(func, "ch_entry");
LLVMBasicBlockRef success = LLVMAppendBasicBlock(func, "ch_success");
LLVMBasicBlockRef end = LLVMAppendBasicBlock(func, "ch_end");
// Basic block: entry
LLVMPositionBuilderAtEnd(builder, entry);
// Call to h_read_bits()
// %read_bits = call i64 @h_read_bits(%struct.HInputStream_* %8, i32 8, i8 signext 0)
LLVMValueRef bits = LLVMBuildCall(builder, LLVMGetNamedFunction(mod, "h_read_bits"), bits_args, 3, "read_bits");
// %2 = trunc i64 %read_bits to i8
LLVMValueRef r = LLVMBuildTrunc(builder, bits, LLVMInt8Type(), ""); // do we actually need this?
// Check if h_read_bits succeeded
// %"c == r" = icmp eq i8 -94, %2 ; the -94 comes from c_
uint8_t c_ = (uint8_t)(uintptr_t)(env);
LLVMValueRef c = LLVMConstInt(LLVMInt8Type(), c_, 0);
LLVMValueRef icmp = LLVMBuildICmp(builder, LLVMIntEQ, c, r, "c == r");
// Branch so success or failure basic block, as appropriate
// br i1 %"c == r", label %ch_success, label %ch_fail
LLVMBuildCondBr(builder, icmp, success, end);
// Basic block: success
LLVMPositionBuilderAtEnd(builder, success);
// Set up call to h_arena_malloc() for a new HParsedToken
LLVMValueRef tok_size = LLVMConstInt(LLVMInt32Type(), sizeof(HParsedToken), 0);
LLVMValueRef amalloc_args[] = { arena, tok_size };
// %h_arena_malloc = call void* @h_arena_malloc(%struct.HArena_.1* %1, i32 48)
LLVMValueRef amalloc = LLVMBuildCall(builder, LLVMGetNamedFunction(mod, "h_arena_malloc"), amalloc_args, 2, "h_arena_malloc");
// %3 = bitcast void* %h_arena_malloc to %struct.HParsedToken_.2*
LLVMValueRef tok = LLVMBuildBitCast(builder, amalloc, llvm_parsedtokenptr, "");
// tok->token_type = TT_UINT;
//
// %token_type = getelementptr inbounds %struct.HParsedToken_.2, %struct.HParsedToken_.2* %3, i32 0, i32 0
LLVMValueRef toktype = LLVMBuildStructGEP(builder, tok, 0, "token_type");
// store i32 8, i32* %token_type
LLVMBuildStore(builder, LLVMConstInt(LLVMInt32Type(), 8, 0), toktype);
// tok->uint = r;
//
// %token_data = getelementptr inbounds %struct.HParsedToken_.2, %struct.HParsedToken_.2* %3, i32 0, i32 1
LLVMValueRef tokdata = LLVMBuildStructGEP(builder, tok, 1, "token_data");
// %r = zext i8 %2 to i64
// store i64 %r, i64* %token_data
LLVMBuildStore(builder, LLVMBuildZExt(builder, r, LLVMInt64Type(), "r"), tokdata);
// %t_index = getelementptr inbounds %struct.HParsedToken_.2, %struct.HParsedToken_.2* %3, i32 0, i32 2
LLVMValueRef tokindex = LLVMBuildStructGEP(builder, tok, 2, "t_index");
// %s_index = getelementptr inbounds %struct.HInputStream_.0, %struct.HInputStream_.0* %0, i32 0, i32 2
LLVMValueRef streamindex = LLVMBuildStructGEP(builder, stream, 2, "s_index");
// %4 = load i64, i64* %s_index
// store i64 %4, i64* %t_index
LLVMBuildStore(builder, LLVMBuildLoad(builder, streamindex, ""), tokindex);
LLVMValueRef tokbitlen = LLVMBuildStructGEP(builder, tok, 3, "bit_length");
LLVMBuildStore(builder, LLVMConstInt(LLVMInt64Type(), 8, 0), tokbitlen);
// Now call make_result()
// %make_result = call %struct.HParseResult_.3* @make_result(%struct.HArena_.1* %1, %struct.HParsedToken_.2* %3)
LLVMValueRef result_args[] = { arena, tok };
LLVMValueRef mr = LLVMBuildCall(builder, LLVMGetNamedFunction(mod, "make_result"), result_args, 2, "make_result");
// br label %ch_end
LLVMBuildBr(builder, end);
// Basic block: end
LLVMPositionBuilderAtEnd(builder, end);
// %rv = phi %struct.HParseResult_.3* [ %make_result, %ch_success ], [ null, %ch_entry ]
LLVMValueRef rv = LLVMBuildPhi(builder, llvm_parseresultptr, "rv");
LLVMBasicBlockRef rv_phi_incoming_blocks[] = {
success,
entry
};
LLVMValueRef rv_phi_incoming_values[] = {
mr,
LLVMConstNull(llvm_parseresultptr)
};
LLVMAddIncoming(rv, rv_phi_incoming_values, rv_phi_incoming_blocks, 2);
// ret %struct.HParseResult_.3* %rv
LLVMBuildRet(builder, rv);
return true;
}
static const HParserVtable ch_vt = { static const HParserVtable ch_vt = {
.parse = parse_ch, .parse = parse_ch,
.isValidRegular = h_true, .isValidRegular = h_true,
.isValidCF = h_true, .isValidCF = h_true,
.desugar = desugar_ch, .desugar = desugar_ch,
.compile_to_rvm = ch_ctrvm, .compile_to_rvm = ch_ctrvm,
.llvm = ch_llvm,
.higher = false, .higher = false,
}; };
......
#ifndef _GNU_SOURCE
#define _GNU_SOURCE // to obtain asprintf/vasprintf #define _GNU_SOURCE // to obtain asprintf/vasprintf
#endif
#include "platform.h" #include "platform.h"
#include <stdio.h> #include <stdio.h>
......
...@@ -116,7 +116,7 @@ static inline bool append_buf_c(struct result_buf *buf, char v) { ...@@ -116,7 +116,7 @@ static inline bool append_buf_c(struct result_buf *buf, char v) {
} }
/** append a formatted string to the result buffer */ /** append a formatted string to the result buffer */
static inline bool append_buf_formatted(struct result_buf *buf, char* format, ...) static inline bool append_buf_formatted(struct result_buf *buf, const char* format, ...)
{ {
char* tmpbuf; char* tmpbuf;
int len; int len;
......
...@@ -961,4 +961,6 @@ void register_parser_tests(void) { ...@@ -961,4 +961,6 @@ void register_parser_tests(void) {
g_test_add_data_func("/core/parser/glr/ambiguous", GINT_TO_POINTER(PB_GLR), test_ambiguous); g_test_add_data_func("/core/parser/glr/ambiguous", GINT_TO_POINTER(PB_GLR), test_ambiguous);
g_test_add_data_func("/core/parser/glr/result_length", GINT_TO_POINTER(PB_GLR), test_result_length); g_test_add_data_func("/core/parser/glr/result_length", GINT_TO_POINTER(PB_GLR), test_result_length);
g_test_add_data_func("/core/parser/glr/token_position", GINT_TO_POINTER(PB_GLR), test_token_position); g_test_add_data_func("/core/parser/glr/token_position", GINT_TO_POINTER(PB_GLR), test_token_position);
g_test_add_data_func("/core/parser/llvm/ch", GINT_TO_POINTER(PB_LLVM), test_ch);
} }
...@@ -167,7 +167,10 @@ static void test_charset_bits(void) { ...@@ -167,7 +167,10 @@ static void test_charset_bits(void) {
.free = NULL, .free = NULL,
}; };
test_charset_bits__buf[32] = 0xAB; test_charset_bits__buf[32] = 0xAB;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-variable"
HCharset cs = new_charset(&alloc); HCharset cs = new_charset(&alloc);
#pragma GCC diagnostic pop
for(size_t i=0; i<32; i++) for(size_t i=0; i<32; i++)
g_check_cmp_uint32(test_charset_bits__buf[i], ==, 0); g_check_cmp_uint32(test_charset_bits__buf[i], ==, 0);
g_check_cmp_uint32(test_charset_bits__buf[32], ==, 0xAB); g_check_cmp_uint32(test_charset_bits__buf[32], ==, 0xAB);
......