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 (7)
......@@ -23,3 +23,4 @@ build/
.sconsign.dblite
*.os
*.pyc
*.ll
\ No newline at end of file
......@@ -100,7 +100,7 @@ if GetOption("coverage"):
if env["CC"] == "gcc":
env.Append(LIBS=['gcov'])
else:
env.ParseConfig('llvm-config --ldflags')
env.ParseConfig('llvm-config --cflags --ldflags --libs core executionengine mcjit analysis x86codegen x86info')
if os.getenv("CC") == "clang" or env['PLATFORM'] == 'darwin':
env.Replace(CC="clang",
......
......@@ -51,7 +51,7 @@ parsers = ['parsers/%s.c'%s for s in
'value']]
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 = [
'allocator.c',
......@@ -76,6 +76,7 @@ ctests = ['t_benchmark.c',
't_misc.c',
't_regression.c']
env.ParseConfig('llvm-config --cflags --ldflags')
libhammer_shared = env.SharedLibrary('hammer', parsers + backends + misc_hammer_parts)
libhammer_static = env.StaticLibrary('hammer', parsers + backends + misc_hammer_parts)
Default(libhammer_shared, libhammer_static)
......@@ -87,8 +88,10 @@ env.Install("$backendsincpath", backends_headers)
env.Install("$pkgconfigpath", "../../../libhammer.pc")
testenv = env.Clone()
testenv.ParseConfig('pkg-config --cflags --libs glib-2.0')
testenv.Append(LIBS=['hammer'], LIBPATH=['.'])
testenv.ParseConfig('pkg-config --cflags --libs glib-2.0')
testenv.ParseConfig('llvm-config --cflags --ldflags --system-libs --libs core executionengine mcjit analysis x86codegen x86info')
testenv.Append(LIBS=['stdc++'], LIBPATH=['.'])
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]))
AlwaysBuild(ctest)
......
#include <llvm-c/Analysis.h>
#include <llvm-c/Core.h>
#include <llvm-c/ExecutionEngine.h>
#include "../internal.h"
#include "../parsers/parser_internal.h"
typedef struct HLLVMParser_ {
LLVMModuleRef mod;
LLVMValueRef func;
LLVMExecutionEngineRef engine;
LLVMBuilderRef builder;
} HLLVMParser;
void h_llvm_declare_common(LLVMModuleRef mod) {
LLVMTypeRef readbits_pt[] = {
LLVMPointerType(LLVMStructCreateNamed(LLVMGetGlobalContext(), "%struct.HInputStream_"), 0),
LLVMInt32Type(),
LLVMInt8Type()
};
LLVMTypeRef readbits_ret = LLVMFunctionType(LLVMInt64Type(), readbits_pt, 3, 0);
LLVMAddFunction(mod, "h_read_bits", readbits_ret);
LLVMTypeRef amalloc_pt[] = {
LLVMPointerType(LLVMStructCreateNamed(LLVMGetGlobalContext(), "%struct.HArena_"), 0),
LLVMInt32Type()
};
LLVMTypeRef amalloc_ret = LLVMFunctionType(LLVMPointerType(LLVMVoidType(), 0), amalloc_pt, 2, 0);
LLVMAddFunction(mod, "h_arena_malloc", amalloc_ret);
LLVMTypeRef makeresult_pt[] = {
LLVMPointerType(LLVMStructCreateNamed(LLVMGetGlobalContext(), "%struct.HArena_"), 0),
LLVMPointerType(LLVMStructCreateNamed(LLVMGetGlobalContext(), "%struct.HParsedToken_"), 0)
};
LLVMTypeRef makeresult_ret = LLVMFunctionType(LLVMPointerType(LLVMStructCreateNamed(LLVMGetGlobalContext(), "%struct.HParseResult_"), 0), 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[] = {
LLVMPointerType(LLVMStructCreateNamed(LLVMGetGlobalContext(), "%struct.HInputStream_"), 0),
LLVMPointerType(LLVMStructCreateNamed(LLVMGetGlobalContext(), "%struct.HArena_"), 0)
};
LLVMTypeRef ret_type = LLVMFunctionType(LLVMPointerType(LLVMStructCreateNamed(LLVMGetGlobalContext(), "%struct.HParseResult_"), 0), param_types, 2, 0);
LLVMValueRef parse_func = LLVMAddFunction(mod, name, ret_type);
// Parse function is now declared; time to define it
LLVMBasicBlockRef entry = LLVMAppendBasicBlock(parse_func, "entry");
LLVMBuilderRef builder = LLVMCreateBuilder();
LLVMPositionBuilderAtEnd(builder, entry);
// Translate the contents of the children of `parser` into their LLVM instruction equivalents
if (parser->vtable->llvm(builder, mod, parser->env)) {
// But first, verification
char *error = NULL;
LLVMVerifyModule(mod, LLVMAbortProcessAction, &error);
LLVMDisposeMessage(error);
error = NULL;
// OK, link that sonofabitch
LLVMInitializeNativeTarget();
LLVMLinkInMCJIT();
LLVMExecutionEngineRef engine = NULL;
LLVMCreateExecutionEngineForModule(&engine, mod, &error);
if (error) {
fprintf(stderr, "error: %s\n", error);
LLVMDisposeMessage(error);
return -1;
}
// 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;
LLVMDisposeBuilder(llvm_parser->builder);
LLVMDisposeExecutionEngine(llvm_parser->engine);
LLVMDisposeModule(llvm_parser->mod);
}
HParseResult *h_llvm_parse(HAllocator* mm__, const HParser* parser, HInputStream *input_stream) {
const HLLVMParser *llvm_parser = parser->backend_data;
LLVMGenericValueRef args[] = { LLVMCreateGenericValueOfPointer(input_stream) };
LLVMGenericValueRef ret = LLVMRunFunction(llvm_parser->engine, llvm_parser->func, 1, args);
return (HParseResult*)LLVMGenericValueToPointer(ret);
}
HParserBackendVTable h__llvm_backend_vtable = {
.compile = h_llvm_compile,
.parse = h_llvm_parse,
.free = h_llvm_free
};
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <string.h>
#include <assert.h>
#include "../internal.h"
......
......@@ -31,6 +31,7 @@ static HParserBackendVTable *backends[PB_MAX + 1] = {
&h__llk_backend_vtable,
&h__lalr_backend_vtable,
&h__glr_backend_vtable,
&h__llvm_backend_vtable,
};
......
......@@ -46,7 +46,8 @@ typedef enum HParserBackend_ {
PB_LLk,
PB_LALR,
PB_GLR,
PB_MAX = PB_GLR
PB_LLVM,
PB_MAX = PB_LLVM
} HParserBackend;
typedef enum HTokenType_ {
......
......@@ -25,6 +25,7 @@
#include <stdint.h>
#include <assert.h>
#include <string.h>
#include <llvm-c/Core.h>
#include "hammer.h"
#include "platform.h"
......@@ -322,6 +323,7 @@ extern HParserBackendVTable h__packrat_backend_vtable;
extern HParserBackendVTable h__llk_backend_vtable;
extern HParserBackendVTable h__lalr_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.
......@@ -419,6 +421,7 @@ struct HParserVtable_ {
bool (*isValidCF)(void *env);
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);
bool (*llvm)(LLVMBuilderRef builder, LLVMModuleRef mod, void *env);
bool higher; // false if primitive
};
......
#include <assert.h>
#include <llvm-c/Core.h>
#include "parser_internal.h"
struct bits_env {
......@@ -17,6 +18,73 @@ static HParseResult* parse_bits(void* env, HParseState *state) {
return make_result(state->arena, result);
}
static bool bits_llvm(LLVMBuilderRef builder, LLVMModuleRef mod, void* env) {
/* %result = alloca %struct.HParsedToken_*, align 8 */
LLVMValueRef result = LLVMBuildAlloca(builder, LLVMPointerType(LLVMStructCreateNamed(LLVMGetGlobalContext(), "%struct.HParsedToken_"), 0), "result");
/* 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) {
// signedp == NULL iff unsigned
bool signedp = (signedp_p != NULL);
......@@ -102,6 +170,7 @@ static const HParserVtable bits_vt = {
.isValidCF = h_true,
.desugar = desugar_bits,
.compile_to_rvm = bits_ctrvm,
.llvm = bits_llvm,
.higher = false,
};
......
#include <stdint.h>
#include <assert.h>
#include <llvm-c/Core.h>
#include "parser_internal.h"
static HParseResult* parse_ch(void* env, HParseState *state) {
......@@ -41,12 +42,110 @@ static bool ch_ctrvm(HRVMProg *prog, void* env) {
return true;
}
static bool ch_llvm(LLVMBuilderRef builder, LLVMModuleRef mod, void* env) {
uint8_t c_ = (uint8_t)(uintptr_t)(env);
LLVMValueRef c = LLVMConstInt(LLVMInt8Type(), c_, 0);
LLVMTypeRef param_types[] = {
LLVMPointerType(LLVMStructCreateNamed(LLVMGetGlobalContext(), "%struct.HInputStream_"), 0),
LLVMPointerType(LLVMStructCreateNamed(LLVMGetGlobalContext(), "%struct.HArena_"), 0)
};
LLVMTypeRef ret_type = LLVMFunctionType(LLVMPointerType(LLVMStructCreateNamed(LLVMGetGlobalContext(), "%struct.HParseResult_*"), 0), param_types, 2, 0);
LLVMValueRef ch = LLVMAddFunction(mod, "ch", ret_type);
// get the parameter array to use later with h_bits
LLVMValueRef bits_args[3];
LLVMGetParams(ch, bits_args);
bits_args[1] = LLVMConstInt(LLVMInt32Type(), 8, 0);
bits_args[2] = LLVMConstInt(LLVMInt8Type(), 0, 0);
LLVMValueRef arena = LLVMGetParam(ch, 1);
LLVMBasicBlockRef entry = LLVMAppendBasicBlock(ch, "ch_entry");
LLVMBasicBlockRef success = LLVMAppendBasicBlock(ch, "ch_success");
LLVMBasicBlockRef fail = LLVMAppendBasicBlock(ch, "ch_fail");
LLVMBasicBlockRef end = LLVMAppendBasicBlock(ch, "ch_end");
LLVMPositionBuilderAtEnd(builder, entry);
// %1 = alloca %struct.HParseResult_*, align 8
LLVMValueRef ret = LLVMBuildAlloca(builder, LLVMPointerType(LLVMStructCreateNamed(LLVMGetGlobalContext(), "%struct.HParseResult_*"), 0), "ret");
// skip %2 through %c because we have these from arguments, and %r because we'll get it later
// %tok = alloca %struct.HParsedToken_*, align 8
LLVMValueRef tok = LLVMBuildAlloca(builder, LLVMPointerType(LLVMStructCreateNamed(LLVMGetGlobalContext(), "%struct.HParsedToken_*"), 0), "tok");
// skip next instr through %8
// %9 = 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, "h_read_bits");
// %10 = trunc i64 %9 to i8
LLVMValueRef r = LLVMBuildTrunc(builder, bits, LLVMInt8Type(), "");
// %11 = load i8* %c
// %12 = zext i8 %11 to i32
// %13 = load i8* %r, align 1
// %14 = zext i8 %13 to i32
// %15 = icmp eq i32 %12, %14
LLVMValueRef icmp = LLVMBuildICmp(builder, LLVMIntEQ, c, r, "c == r");
// br i1 %15, label %16, label %34
LLVMBuildCondBr(builder, icmp, success, fail);
// ; <label>:16 - success case
LLVMPositionBuilderAtEnd(builder, success);
// skip %17-%19 because we have the arena as an argument
LLVMValueRef tok_size = LLVMConstInt(LLVMInt32Type(), sizeof(HParsedToken), 0);
LLVMValueRef amalloc_args[] = { arena, tok_size };
// %20 = call noalias i8* @h_arena_malloc(%struct.HArena_* %19, i64 48)
LLVMValueRef amalloc = LLVMBuildCall(builder, LLVMGetNamedFunction(mod, "h_arena_malloc"), amalloc_args, 2, "h_arena_malloc");
// %21 = bitcast i8* %20 to %struct.HParsedToken_*
LLVMValueRef cast1 = LLVMBuildBitCast(builder, amalloc, LLVMPointerType(LLVMStructCreateNamed(LLVMGetGlobalContext(), "%struct.HParsedToken_"), 0), "");
// store %struct.HParsedToken_* %21, %struct.HParsedToken_** %tok, align 8
LLVMBuildStore(builder, cast1, tok);
// %22 = load %struct.HParsedToken_** %tok, align 8
// %23 = getelementptr inbounds %struct.HParsedToken_* %22, i32 0, i32 0
LLVMValueRef bounds1[] = {
LLVMConstInt(LLVMInt32Type(), 0, 0),
LLVMConstInt(LLVMInt32Type(), 0, 0)
};
LLVMValueRef toktype = LLVMBuildInBoundsGEP(builder, tok, bounds1, 0, "token_type");
// store i32 8, i32* %23, align 4
LLVMBuildStore(builder, LLVMConstInt(LLVMInt32Type(), 8, 0), toktype);
// %24 = load i8* %r, align 1
// %25 = zext i8 %24 to i64
// %26 = load %struct.HParsedToken_** %tok, align 8
// %27 = getelementptr inbounds %struct.HParsedToken_* %26, i32 0, i32 1
/* LLVMValueRef bounds2[] = { */
/* LLVMConstInt(LLVMInt32Type(), 0, 0), */
/* LLVMConstInt(LLVMInt32Type(), 0, 1) */
/* }; */
/* LLVMValueRef uint = LLVMBuildInBoundsGEP(builder, tok, bounds2, 1, "uint"); */
// %28 = bitcast %union.anon* %27 to i64*
//LLVMValueRef cast2 = LLVMBuildBitCast(builder, uint, LLVMInt64Type(), "result");
LLVMValueRef uint = LLVMConstInt(LLVMInt32Type(), TT_UINT, 0);
LLVMBuildInsertValue(builder, tok, uint, 0, 0);
LLVMBuildInsertValue(builder, tok, r, 1, 0);
// we already have the arena and the token, so skip to %33
// %33 = call %struct.HParseResult_* @make_result(%struct.HArena_* %31, %struct.HParsedToken_* %32)
LLVMValueRef result_args[] = { arena, tok };
LLVMValueRef mr = LLVMBuildCall(builder, LLVMGetNamedFunction(mod, "make_result"), result_args, 2, "make_result");
// store %struct.HParseResult_* %33, %struct.HParseResult_** %1
LLVMBuildStore(builder, mr, ret);
// br label %35
LLVMBuildBr(builder, end);
// ; <label>:34 - failure case
LLVMPositionBuilderAtEnd(builder, fail);
// store %struct.HParseResult* null, %struct.HParseResult_** %1
LLVMBuildStore(builder, LLVMConstNull(LLVMPointerType(LLVMStructCreateNamed(LLVMGetGlobalContext(), "%struct.HParsedToken"), 0)), ret);
// br label %35
LLVMBuildBr(builder, end);
// ; <label>:35
LLVMPositionBuilderAtEnd(builder, end);
// %36 = load %struct.HParseResult_** %1
// ret %struct.HParseResult_* %36
LLVMBuildRet(builder, ret);
return true;
}
static const HParserVtable ch_vt = {
.parse = parse_ch,
.isValidRegular = h_true,
.isValidCF = h_true,
.desugar = desugar_ch,
.compile_to_rvm = ch_ctrvm,
.llvm = ch_llvm,
.higher = false,
};
......
#ifndef _GNU_SOURCE
#define _GNU_SOURCE // to obtain asprintf/vasprintf
#endif
#include "platform.h"
#include <stdio.h>
......
......@@ -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/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/llvm/ch", GINT_TO_POINTER(PB_LLVM), test_ch);
}