From 8dcb3fed548dbb8c25aa9958e9b683af574b6782 Mon Sep 17 00:00:00 2001 From: "Meredith L. Patterson" <mlp@thesmartpolitenerd.com> Date: Wed, 24 Feb 2016 06:52:30 +0100 Subject: [PATCH] converting the simplest combinators to LLVM IR --- src/parsers/bits.c | 69 ++++++++++++++++++++++++++++++ src/parsers/ch.c | 104 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 173 insertions(+) diff --git a/src/parsers/bits.c b/src/parsers/bits.c index be8f13f1..12823285 100644 --- a/src/parsers/bits.c +++ b/src/parsers/bits.c @@ -1,4 +1,5 @@ #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, }; diff --git a/src/parsers/ch.c b/src/parsers/ch.c index 3da1091a..d7743bc9 100644 --- a/src/parsers/ch.c +++ b/src/parsers/ch.c @@ -1,5 +1,6 @@ #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,115 @@ 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(LLVMInt8Type(), 0) }; + LLVMTypeRef ret_type = LLVMFunctionType(LLVMPointerType(LLVMStructCreateNamed(LLVMGetGlobalContext(), "%struct.HParseResult_"), 0), param_types, 1, 0); + LLVMValueRef ch = LLVMAddFunction(mod, "ch", ret_type); + 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 + // FIXME declare struct types like LL_HParsedToken with LLVMStructType() in some other header + LLVMValueRef ret = LLVMBuildAlloca(builder, LLVMPointerType(LLVMStructCreateNamed(LLVMGetGlobalContext(), "%struct.HParseResult_"), 0), "ret"); + // skip %2 through %c 'cause we have these from arguments + // %r = alloca i8, align 1 + LLVMValueRef r = LLVMBuildAlloca(builder, LLVMInt8Type(), "r"); + // %tok = alloca %struct.HParsedToken_*, align 8 + LLVMValueRef tok = LLVMBuildAlloca(builder, LLVMPointerType(LLVMStructCreateNamed(LLVMGetGlobalContext(), "%struct.HParsedToken_"), 0), "tok"); + // skip next instr through %7 + // %8 = getelementptr inbounds %struct.HParseState_* %7, i32 0, i32 1 + LLVMValueRef bounds1[] = { + LLVMConstInt(LLVMInt32Type(), 0, 0), + LLVMConstInt(LLVMInt32Type(), 1, 0), + }; + /* FIXME env is the wrong pointer to use here */ + LLVMValueRef stream = LLVMBuildInBoundsGEP(builder, env, bounds1, 1, "stream"); + // %9 = call i64 @h_read_bits(%struct.HInputStream_* %8, i32 8, i8 signext 0) + LLVMValueRef bits = LLVMBuildCall(builder, LLVMGetNamedFunction(mod, "h_read_bits"), &stream, 1, "h_read_bits"); + // %10 = trunc i64 %9 to i8 + LLVMValueRef tmp = LLVMBuildTrunc(builder, bits, LLVMInt8Type(), ""); + // store i8 %10, i8* %r, align 1 + LLVMBuildStore(builder, bits, r); + // %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); + // %17 = load %struct.HParseState_** %3, align 8 + // %18 = getelementptr inbounds %struct.HParseState_* %17, i32 0, i32 2 + LLVMValueRef bounds2[] = { + LLVMConstInt(LLVMInt32Type(), 0, 0), + LLVMConstInt(LLVMInt32Type(), 2, 0), + }; + /* FIXME env is not the right pointer to use here */ + LLVMValueRef arena = LLVMBuildInBoundsGEP(builder, env, bounds2, 2, "arena"); + // %20 = call noalias i8* @h_arena_malloc(%struct.HArena_* %19, i64 48) + LLVMValueRef amalloc = LLVMBuildCall(builder, LLVMGetNamedFunction(mod, "h_arena_malloc"), &arena, 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 bounds3[] = { + LLVMConstInt(LLVMInt32Type(), 0, 0), + LLVMConstInt(LLVMInt32Type(), 0, 0) + }; + LLVMValueRef toktype = LLVMBuildInBoundsGEP(builder, tok, bounds3, 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 uint = LLVMBuildInBoundsGEP(builder, tok, bounds1, 1, "uint"); + // %28 = bitcast %union.anon* %27 to i64* + LLVMValueRef cast2 = LLVMBuildBitCast(builder, uint, LLVMInt64Type(), "result"); + // we already have the arena and the token, so skip to %33 + // %29 = load %struct.HParseState_** %3, align 8 + // %30 = getelementptr inbounds %struct.HParseState_* %29, i32 0, i32 2 + // %31 = load %struct.HArena_** %30, align 8 + // %32 = load %struct.HParsedToken_** %tok, align 8 + // %33 = call %struct.HParseResult_* @make_result(%struct.HArena_* %31, %struct.HParsedToken_* %32) + LLVMValueRef args[] = { arena, tok }; + LLVMValueRef mr = LLVMBuildCall(builder, LLVMGetNamedFunction(mod, "make_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, }; -- GitLab