diff --git a/src/parsers/int_range.c b/src/parsers/int_range.c index 49b064218b507ca13d90dcc2ec654c8ae3a9ee19..8d536f3b2afc8caeab72ffb05d6aa3802dfd37c7 100644 --- a/src/parsers/int_range.c +++ b/src/parsers/int_range.c @@ -1,5 +1,12 @@ -#include "parser_internal.h" +#ifdef HAMMER_LLVM_BACKEND +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" +#include <llvm-c/Core.h> +#pragma GCC diagnostic pop +#include "../backends/llvm/llvm.h" +#endif +#include "parser_internal.h" typedef struct { const HParser *p; @@ -111,12 +118,629 @@ static bool ir_ctrvm(HRVMProg *prog, void *env) { return false; } +#ifdef HAMMER_LLVM_BACKEND + +static bool ir_llvm(HLLVMParserCompileContext *ctxt, + const HParser *p, + LLVMValueRef *res) { + /* Build some LLVM IR to parse an intrange */ + + /* The allocator */ + HAllocator *mm__ = NULL; + /* Names */ + char *ir_entry_name = NULL; + int ir_entry_name_len = 0; + char *ir_check_res_name = NULL; + int ir_check_res_name_len = 0; + char *ir_check_res_ast_name = NULL; + int ir_check_res_ast_name_len = 0; + char *ir_check_token_type_name = NULL; + int ir_check_token_type_name_len = 0; + char *ir_check_tt_uint_name = NULL; + int ir_check_tt_uint_name_len = 0; + char *ir_check_tt_sint_name = NULL; + int ir_check_tt_sint_name_len = 0; + char *ir_handle_tt_uint_name = NULL; + int ir_handle_tt_uint_name_len = 0; + char *ir_handle_tt_sint_name = NULL; + int ir_handle_tt_sint_name_len = 0; + char *ir_check_bounds_name = NULL; + int ir_check_bounds_name_len = 0; + char *ir_check_upper_bound_name = NULL; + int ir_check_upper_bound_name_len = 0; + char *ir_success_name = NULL; + int ir_success_name_len = 0; + char *ir_fail_name = NULL; + int ir_fail_name_len = 0; + char *ir_end_name = NULL; + int ir_end_name_len = 0; + char *inner_res_icmp_name = NULL; + int inner_res_icmp_name_len = 0; + char *ret_ast_ptr_name = NULL; + int ret_ast_ptr_name_len = 0; + char *ret_ast_name = NULL; + int ret_ast_name_len = 0; + char *ret_ast_icmp_name = NULL; + int ret_ast_icmp_name_len = 0; + char *token_type_ptr_name = NULL; + int token_type_ptr_name_len = 0; + char *token_type_name = NULL; + int token_type_name_len = 0; + char *token_length_ptr_name = NULL; + int token_length_ptr_name_len = 0; + char *token_length_name = NULL; + int token_length_name_len = 0; + char *token_data_ptr_name = NULL; + int token_data_ptr_name_len = 0; + char *token_data_name = NULL; + int token_data_name_len = 0; + char *tt_uint_icmp_name = NULL; + int tt_uint_icmp_name_len = 0; + char *tt_sint_icmp_name = NULL; + int tt_sint_icmp_name_len = 0; + char *lower_uint_icmp_name = NULL; + int lower_uint_icmp_name_len = 0; + char *lower_sint_icmp_name = NULL; + int lower_sint_icmp_name_len = 0; + char *lower_icmp_name = NULL; + int lower_icmp_name_len = 0; + char *upper_uint_icmp_name = NULL; + int upper_uint_icmp_name_len = 0; + char *upper_sint_icmp_name = NULL; + int upper_sint_icmp_name_len = 0; + char *upper_icmp_name = NULL; + int upper_icmp_name_len = 0; + char *rv_name = NULL; + int rv_name_len = 0; + /* The HRange */ + HRange *r = NULL; + /* Our status */ + bool status = true; + /* intrange basic blocks */ + LLVMBasicBlockRef entry, check_res, check_res_ast, check_token_type; + LLVMBasicBlockRef check_tt_uint, check_tt_sint, handle_tt_uint, handle_tt_sint; + LLVMBasicBlockRef check_bounds, check_upper_bound; + LLVMBasicBlockRef success, fail, end; + /* Result of the parser this intrange wraps */ + LLVMValueRef inner_res; + /* Result of result-not-zero icmp */ + LLVMValueRef inner_res_icmp; + /* Pointer to AST pointer from inner_res */ + LLVMValueRef ret_ast_ptr; + /* AST pointer from inner_res */ + LLVMValueRef ret_ast; + /* Result of res_ast != 0 icmp */ + LLVMValueRef ret_ast_icmp; + /* Pointer to token type from ret->ast */ + LLVMValueRef token_type_ptr; + /* Value of token type from ret->ast */ + LLVMValueRef token_type; + /* Pointer to token length from ret->ast */ + LLVMValueRef token_length_ptr; + /* Value of token length from ret->ast */ + LLVMValueRef token_length; + /* Pointer to token data from ret->ast */ + LLVMValueRef token_data_ptr; + /* Value of token data from ret->ast */ + LLVMValueRef token_data; + /* Result of comparing token_type to TT_UINT */ + LLVMValueRef tt_uint_icmp; + /* Result of comparing token_type to TT_SINT */ + LLVMValueRef tt_sint_icmp; + /* Result of icmp against lower bound */ + LLVMValueRef lower_sint_icmp, lower_uint_icmp, lower_icmp; + /* Result of icmp against upper bound */ + LLVMValueRef upper_sint_icmp, upper_uint_icmp, upper_icmp; + /* Inputs to the phis for lower_icmp and upper_icmp */ + LLVMBasicBlockRef lower_icmp_incoming_blocks[2]; + LLVMValueRef lower_icmp_incoming_values[2]; + LLVMBasicBlockRef upper_icmp_incoming_blocks[2]; + LLVMValueRef upper_icmp_incoming_values[2]; + /* Our result */ + LLVMValueRef rv; + /* Inputs to the phi */ + LLVMBasicBlockRef rv_phi_incoming_blocks[2]; + LLVMValueRef rv_phi_incoming_values[2]; + /* Width of the integer in the token type */ + unsigned int token_int_width; + + + if (!res) return false; + if (!p) return false; + if (!ctxt) return false; + + /* Unpack the allocator */ + mm__ = ctxt->mm__; + + /* Get the range */ + r = (HRange *)(p->env); + if (!r) return false; + + /* Set up our basic blocks */ + ir_entry_name_len = snprintf(NULL, 0, "ir_entry_%p", p); + ir_entry_name = h_new(char, ir_entry_name_len + 1); + snprintf(ir_entry_name, ir_entry_name_len + 1, + "ir_entry_%p", p); + entry = LLVMAppendBasicBlock(ctxt->func, ir_entry_name); + ir_check_res_name_len = snprintf(NULL, 0, "ir_check_res_%p", p); + ir_check_res_name = h_new(char, ir_check_res_name_len + 1); + snprintf(ir_check_res_name, ir_check_res_name_len + 1, + "ir_check_res_%p", p); + check_res = LLVMAppendBasicBlock(ctxt->func, ir_check_res_name); + ir_check_res_ast_name_len = snprintf(NULL, 0, "ir_check_res_ast_%p", p); + ir_check_res_ast_name = h_new(char, ir_check_res_ast_name_len + 1); + snprintf(ir_check_res_ast_name, ir_check_res_ast_name_len + 1, + "ir_check_res_ast_%p", p); + check_res_ast = LLVMAppendBasicBlock(ctxt->func, ir_check_res_ast_name); + ir_check_token_type_name_len = + snprintf(NULL, 0, "ir_check_token_type_%p", p); + ir_check_token_type_name = h_new(char, ir_check_token_type_name_len + 1); + snprintf(ir_check_token_type_name, ir_check_token_type_name_len + 1, + "ir_check_token_type_%p", p); + check_token_type = + LLVMAppendBasicBlock(ctxt->func, ir_check_token_type_name); + ir_check_tt_uint_name_len = + snprintf(NULL, 0, "ir_check_tt_uint_%p", p); + ir_check_tt_uint_name = h_new(char, ir_check_tt_uint_name_len + 1); + snprintf(ir_check_tt_uint_name, ir_check_tt_uint_name_len + 1, + "ir_check_tt_uint_%p", p); + check_tt_uint = + LLVMAppendBasicBlock(ctxt->func, ir_check_tt_uint_name); + ir_check_tt_sint_name_len = + snprintf(NULL, 0, "ir_check_tt_sint_%p", p); + ir_check_tt_sint_name = h_new(char, ir_check_tt_sint_name_len + 1); + snprintf(ir_check_tt_sint_name, ir_check_tt_sint_name_len + 1, + "ir_check_tt_sint_%p", p); + check_tt_sint = + LLVMAppendBasicBlock(ctxt->func, ir_check_tt_sint_name); + ir_handle_tt_uint_name_len = + snprintf(NULL, 0, "ir_handle_tt_uint_%p", p); + ir_handle_tt_uint_name = h_new(char, ir_handle_tt_uint_name_len + 1); + snprintf(ir_handle_tt_uint_name, ir_handle_tt_uint_name_len + 1, + "ir_handle_tt_uint_%p", p); + handle_tt_uint = + LLVMAppendBasicBlock(ctxt->func, ir_handle_tt_uint_name); + ir_handle_tt_sint_name_len = + snprintf(NULL, 0, "ir_handle_tt_sint_%p", p); + ir_handle_tt_sint_name = h_new(char, ir_handle_tt_sint_name_len + 1); + snprintf(ir_handle_tt_sint_name, ir_handle_tt_sint_name_len + 1, + "ir_handle_tt_sint_%p", p); + handle_tt_sint = + LLVMAppendBasicBlock(ctxt->func, ir_handle_tt_sint_name); + ir_check_bounds_name_len = snprintf(NULL, 0, "ir_check_bounds_%p", p); + ir_check_bounds_name = h_new(char, ir_check_bounds_name_len + 1); + snprintf(ir_check_bounds_name, ir_check_bounds_name_len + 1, + "ir_check_bounds_%p", p); + check_bounds = LLVMAppendBasicBlock(ctxt->func, ir_check_bounds_name); + ir_check_upper_bound_name_len = + snprintf(NULL, 0, "ir_check_upper_bound_%p", p); + ir_check_upper_bound_name = + h_new(char, ir_check_upper_bound_name_len + 1); + snprintf(ir_check_upper_bound_name, ir_check_upper_bound_name_len + 1, + "ir_check_upper_bound_%p", p); + check_upper_bound = LLVMAppendBasicBlock(ctxt->func, + ir_check_upper_bound_name); + ir_success_name_len = snprintf(NULL, 0, "ir_success_%p", p); + ir_success_name = h_new(char, ir_success_name_len + 1); + snprintf(ir_success_name, ir_success_name_len + 1, + "ir_success_%p", p); + success = LLVMAppendBasicBlock(ctxt->func, ir_success_name); + ir_fail_name_len = snprintf(NULL, 0, "ir_fail_%p", p); + ir_fail_name = h_new(char, ir_fail_name_len + 1); + snprintf(ir_fail_name, ir_fail_name_len + 1, + "ir_fail_%p", p); + fail = LLVMAppendBasicBlock(ctxt->func, ir_fail_name); + ir_end_name_len = snprintf(NULL, 0, "ir_end_%p", p); + ir_end_name = h_new(char, ir_end_name_len + 1); + snprintf(ir_end_name, ir_end_name_len + 1, + "ir_end_%p", p); + end = LLVMAppendBasicBlock(ctxt->func, ir_end_name); + + /* Basic block: entry */ + LLVMBuildBr(ctxt->builder, entry); + LLVMPositionBuilderAtEnd(ctxt->builder, entry); + + /* Try the inner parser */ + if (r->p && r->p->vtable && r->p->vtable->llvm) { + if (r->p->vtable->llvm(ctxt, r->p, &inner_res)) { + /* w00t, the inner parser compiled */ + + /* + * Okay, now we should have a pointer to an HParseResult in inner_res, + * and we need to check that the result is a TT_SINT or a TT_UINT and + * matches the required range. + * + * XXX we could probably look at the type of parser we have under the + * h_int_range at compile time and build a fast-path common case. + */ + + /* Set up the int_range bb */ + LLVMBuildBr(ctxt->builder, check_res); + + /* Check that the result is not null */ + LLVMPositionBuilderAtEnd(ctxt->builder, check_res); + inner_res_icmp_name_len = snprintf(NULL, 0, + "ir_inner_res_null_icmp_%p", p); + inner_res_icmp_name = h_new(char, inner_res_icmp_name_len + 1); + snprintf(inner_res_icmp_name, inner_res_icmp_name_len + 1, + "ir_inner_res_null_icmp_%p", p); + inner_res_icmp = LLVMBuildICmp(ctxt->builder, LLVMIntNE, + inner_res, LLVMConstNull(ctxt->llvm_parseresultptr), + inner_res_icmp_name); + LLVMBuildCondBr(ctxt->builder, inner_res_icmp, check_res_ast, fail); + + /* First, get the AST pointer out */ + LLVMPositionBuilderAtEnd(ctxt->builder, check_res_ast); + ret_ast_ptr_name_len = snprintf(NULL, 0, "ret_ast_ptr_%p", p); + ret_ast_ptr_name = h_new(char, ret_ast_ptr_name_len + 1); + snprintf(ret_ast_ptr_name, ret_ast_ptr_name_len + 1, + "ret_ast_ptr_%p", p); + ret_ast_ptr = LLVMBuildStructGEP(ctxt->builder, inner_res, + 0, ret_ast_ptr_name); + + /* Deref ret_ast_ptr */ + ret_ast_name_len = snprintf(NULL, 0, "ret_ast_%p", p); + ret_ast_name = h_new(char, ret_ast_name_len + 1); + snprintf(ret_ast_name, ret_ast_name_len + 1, + "ret_ast_%p", p); + ret_ast = LLVMBuildLoad(ctxt->builder, ret_ast_ptr, ret_ast_name); + + /* Check that the AST pointer is not null */ + ret_ast_icmp_name_len = snprintf(NULL, 0, + "ir_ret_ast_null_icmp_%p", p); + ret_ast_icmp_name = h_new(char, ret_ast_icmp_name_len + 1); + snprintf(ret_ast_icmp_name, ret_ast_icmp_name_len + 1, + "ir_ret_ast_null_icmp_%p", p); + ret_ast_icmp = LLVMBuildICmp(ctxt->builder, LLVMIntNE, + ret_ast, LLVMConstNull(ctxt->llvm_parsedtokenptr), + ret_ast_icmp_name); + LLVMBuildCondBr(ctxt->builder, ret_ast_icmp, check_token_type, fail); + + /* Holly shit, it's a real token! */ + LLVMPositionBuilderAtEnd(ctxt->builder, check_token_type); + token_type_ptr_name_len = snprintf(NULL, 0, "ir_token_type_ptr_%p", p); + token_type_ptr_name = h_new(char, token_type_ptr_name_len + 1); + snprintf(token_type_ptr_name, token_type_ptr_name_len + 1, + "ir_token_type_ptr_%p", p); + token_type_ptr = LLVMBuildStructGEP(ctxt->builder, ret_ast, + 0, token_type_ptr_name); + token_type_name_len = snprintf(NULL, 0, "ir_token_type_%p", p); + token_type_name = h_new(char, token_type_name_len + 1); + snprintf(token_type_name, token_type_name_len + 1, + "ir_token_type_%p", p); + token_type = + LLVMBuildLoad(ctxt->builder, token_type_ptr, token_type_name); + token_data_ptr_name_len = + snprintf(NULL, 0, "ir_token_data_ptr_%p", p); + token_data_ptr_name = h_new(char, token_data_ptr_name_len + 1); + snprintf(token_data_ptr_name, token_data_ptr_name_len + 1, + "ir_token_data_ptr_%p", p); + token_data_ptr = LLVMBuildStructGEP(ctxt->builder, ret_ast, + 1, token_data_ptr_name); + token_data_name_len = snprintf(NULL, 0, "ir_token_data_%p", p); + token_data_name = h_new(char, token_data_name_len + 1); + snprintf(token_data_name, token_data_name_len + 1, + "ir_token_data_%p", p); + token_data = + LLVMBuildLoad(ctxt->builder, token_data_ptr, token_data_name); + /* Now check if we have a TT_UINT */ + LLVMBuildBr(ctxt->builder, check_tt_uint); + + /* Are we doing a TT_UINT? */ + LLVMPositionBuilderAtEnd(ctxt->builder, check_tt_uint); + tt_uint_icmp_name_len = snprintf(NULL, 0, "ir_tt_uint_icmp_%p", p); + tt_uint_icmp_name = h_new(char, tt_uint_icmp_name_len + 1); + snprintf(tt_uint_icmp_name, tt_uint_icmp_name_len + 1, + "ir_tt_uint_null_icmp_%p", p); + tt_uint_icmp = LLVMBuildICmp(ctxt->builder, LLVMIntEQ, + token_type, LLVMConstInt(LLVMInt32Type(), TT_UINT, 0), + tt_uint_icmp_name); + LLVMBuildCondBr(ctxt->builder, tt_uint_icmp, handle_tt_uint, check_tt_sint); + + /* Are we doing a TT_SINT? */ + LLVMPositionBuilderAtEnd(ctxt->builder, check_tt_sint); + tt_sint_icmp_name_len = snprintf(NULL, 0, "ir_tt_sint_icmp_%p", p); + tt_sint_icmp_name = h_new(char, tt_sint_icmp_name_len + 1); + snprintf(tt_sint_icmp_name, tt_sint_icmp_name_len + 1, + "ir_tt_sint_null_icmp_%p", p); + tt_sint_icmp = LLVMBuildICmp(ctxt->builder, LLVMIntEQ, + token_type, LLVMConstInt(LLVMInt32Type(), TT_SINT, 0), + tt_sint_icmp_name); + LLVMBuildCondBr(ctxt->builder, tt_sint_icmp, handle_tt_sint, fail); + + /* + * No need to dick around with sext/zext on token_data because + * it was already done on token creation; see h_llvm_make_tt_suint() + */ + + /* Handle the TT_UINT case */ + LLVMPositionBuilderAtEnd(ctxt->builder, handle_tt_uint); + lower_uint_icmp_name_len = + snprintf(NULL, 0, "lower_uint_icmp_%p", p); + lower_uint_icmp_name = h_new(char, lower_uint_icmp_name_len + 1); + snprintf(lower_uint_icmp_name, lower_uint_icmp_name_len + 1, + "lower_uint_icmp_%p", p); + lower_uint_icmp = LLVMBuildICmp(ctxt->builder, LLVMIntULT, + token_data, + LLVMConstInt(LLVMTypeOf(token_data), (uint64_t)(r->lower), 0), + lower_uint_icmp_name); + upper_uint_icmp_name_len = + snprintf(NULL, 0, "upper_uint_icmp_%p", p); + upper_uint_icmp_name = h_new(char, upper_uint_icmp_name_len + 1); + snprintf(upper_uint_icmp_name, upper_uint_icmp_name_len + 1, + "upper_uint_icmp_%p", p); + upper_uint_icmp = LLVMBuildICmp(ctxt->builder, LLVMIntUGT, + token_data, + LLVMConstInt(LLVMTypeOf(token_data), (uint64_t)(r->upper), 0), + upper_uint_icmp_name); + LLVMBuildBr(ctxt->builder, check_bounds); + + /* Handle the TT_SINT case */ + LLVMPositionBuilderAtEnd(ctxt->builder, handle_tt_sint); + lower_sint_icmp_name_len = + snprintf(NULL, 0, "lower_sint_icmp_%p", p); + lower_sint_icmp_name = h_new(char, lower_sint_icmp_name_len + 1); + snprintf(lower_sint_icmp_name, lower_sint_icmp_name_len + 1, + "lower_sint_icmp_%p", p); + lower_sint_icmp = LLVMBuildICmp(ctxt->builder, LLVMIntSLT, + token_data, + LLVMConstInt(LLVMTypeOf(token_data), (int64_t)(r->lower), 0), + lower_sint_icmp_name); + upper_sint_icmp_name_len = + snprintf(NULL, 0, "upper_sint_icmp_%p", p); + upper_sint_icmp_name = h_new(char, upper_sint_icmp_name_len + 1); + snprintf(upper_sint_icmp_name, upper_sint_icmp_name_len + 1, + "upper_sint_icmp_%p", p); + upper_sint_icmp = LLVMBuildICmp(ctxt->builder, LLVMIntSGT, + token_data, + LLVMConstInt(LLVMTypeOf(token_data), (int64_t)(r->upper), 0), + upper_sint_icmp_name); + LLVMBuildBr(ctxt->builder, check_bounds); + + /* + * The check_bounds block can come in from handle_tt_uint or + * handle_tt_sint, so the icmps it uses are phis + */ + LLVMPositionBuilderAtEnd(ctxt->builder, check_bounds); + lower_icmp_name_len = snprintf(NULL, 0, "lower_icmp_%p", p); + lower_icmp_name = h_new(char, lower_icmp_name_len + 1); + snprintf(lower_icmp_name, lower_icmp_name_len + 1, + "lower_icmp_%p", p); + lower_icmp = LLVMBuildPhi(ctxt->builder, + LLVMTypeOf(lower_uint_icmp), lower_icmp_name); + lower_icmp_incoming_blocks[0] = handle_tt_uint; + lower_icmp_incoming_values[0] = lower_uint_icmp; + lower_icmp_incoming_blocks[1] = handle_tt_sint; + lower_icmp_incoming_values[1] = lower_sint_icmp; + LLVMAddIncoming(lower_icmp, + lower_icmp_incoming_values, + lower_icmp_incoming_blocks, + 2); + upper_icmp_name_len = snprintf(NULL, 0, "upper_icmp_%p", p); + upper_icmp_name = h_new(char, upper_icmp_name_len + 1); + snprintf(upper_icmp_name, upper_icmp_name_len + 1, + "upper_icmp_%p", p); + upper_icmp = LLVMBuildPhi(ctxt->builder, + LLVMTypeOf(upper_uint_icmp), upper_icmp_name); + upper_icmp_incoming_blocks[0] = handle_tt_uint; + upper_icmp_incoming_values[0] = upper_uint_icmp; + upper_icmp_incoming_blocks[1] = handle_tt_sint; + upper_icmp_incoming_values[1] = upper_sint_icmp; + LLVMAddIncoming(upper_icmp, + upper_icmp_incoming_values, + upper_icmp_incoming_blocks, + 2); + /* Did we fail the lower bound? */ + LLVMBuildCondBr(ctxt->builder, lower_icmp, fail, check_upper_bound); + + /* Okay, now we check the upper one */ + LLVMPositionBuilderAtEnd(ctxt->builder, check_upper_bound); + LLVMBuildCondBr(ctxt->builder, upper_icmp, fail, success); + + /* + * From success, branch to end (and the phi for rv will know to + * use ret) + */ + LLVMPositionBuilderAtEnd(ctxt->builder, success); + LLVMBuildBr(ctxt->builder, end); + + /* + * From fail, branch to end (and the phi for rv will know to + * use NULL) + */ + LLVMPositionBuilderAtEnd(ctxt->builder, fail); + LLVMBuildBr(ctxt->builder, end); + + /* + * In end, phi for rv + */ + LLVMPositionBuilderAtEnd(ctxt->builder, end); + rv_name_len = snprintf(NULL, 0, "int_range_rv_%p", p); + rv_name = h_new(char, rv_name_len + 1); + snprintf(rv_name, rv_name_len + 1, "int_range_rv_%p", p); + rv = LLVMBuildPhi(ctxt->builder, ctxt->llvm_parseresultptr, rv_name); + rv_phi_incoming_blocks[0] = success; + rv_phi_incoming_values[0] = inner_res; + rv_phi_incoming_blocks[1] = fail; + rv_phi_incoming_values[1] = LLVMConstNull(ctxt->llvm_parseresultptr); + LLVMAddIncoming(rv, rv_phi_incoming_values, rv_phi_incoming_blocks, 2); + *res = rv; + + /* Pass it back out */ + *res = rv; + } else { + status = false; + } + } else { + status = false; + } + + /* Free names */ + + if (ir_entry_name) { + h_free(ir_entry_name); + ir_entry_name = NULL; + } + + if (ir_check_res_name) { + h_free(ir_check_res_name); + ir_check_res_name = NULL; + } + + if (ir_check_res_ast_name) { + h_free(ir_check_res_ast_name); + ir_check_res_ast_name = NULL; + } + + if (ir_check_token_type_name) { + h_free(ir_check_token_type_name); + ir_check_token_type_name = NULL; + } + + if (ir_handle_tt_uint_name) { + h_free(ir_handle_tt_uint_name); + ir_handle_tt_uint_name = NULL; + } + + if (ir_handle_tt_sint_name) { + h_free(ir_handle_tt_sint_name); + ir_handle_tt_sint_name = NULL; + } + + if (ir_check_tt_uint_name) { + h_free(ir_check_tt_uint_name); + ir_check_tt_uint_name = NULL; + } + + if (ir_check_tt_sint_name) { + h_free(ir_check_tt_sint_name); + ir_check_tt_sint_name = NULL; + } + + if (ir_check_bounds_name) { + h_free(ir_check_bounds_name); + ir_check_bounds_name = NULL; + } + + if (ir_check_upper_bound_name) { + h_free(ir_check_upper_bound_name); + ir_check_upper_bound_name = NULL; + } + + if (ir_success_name) { + h_free(ir_success_name); + ir_success_name = NULL; + } + + if (ir_fail_name) { + h_free(ir_fail_name); + ir_fail_name = NULL; + } + + if (ir_end_name) { + h_free(ir_end_name); + ir_end_name = NULL; + } + + if (inner_res_icmp_name) { + h_free(inner_res_icmp_name); + inner_res_icmp_name = NULL; + } + + if (ret_ast_ptr_name) { + h_free(ret_ast_ptr_name); + ret_ast_ptr_name = NULL; + } + + if (ret_ast_name) { + h_free(ret_ast_name); + ret_ast_name = NULL; + } + + if (ret_ast_icmp_name) { + h_free(ret_ast_icmp_name); + ret_ast_icmp_name = NULL; + } + + if (token_type_ptr_name) { + h_free(token_type_ptr_name); + token_type_ptr_name = NULL; + } + + if (token_type_name) { + h_free(token_type_name); + token_type_name = NULL; + } + + if (token_data_ptr_name) { + h_free(token_data_ptr_name); + token_data_ptr_name = NULL; + } + + if (token_data_name) { + h_free(token_data_name); + token_data_name = NULL; + } + + if (tt_uint_icmp_name) { + h_free(tt_uint_icmp_name); + tt_uint_icmp_name = NULL; + } + + if (tt_sint_icmp_name) { + h_free(tt_sint_icmp_name); + tt_sint_icmp_name = NULL; + } + + if (lower_uint_icmp_name) { + h_free(lower_uint_icmp_name); + lower_uint_icmp_name = NULL; + } + + if (lower_sint_icmp_name) { + h_free(lower_sint_icmp_name); + lower_sint_icmp_name = NULL; + } + + if (lower_icmp_name) { + h_free(lower_icmp_name); + lower_icmp_name = NULL; + } + + if (upper_uint_icmp_name) { + h_free(upper_uint_icmp_name); + upper_uint_icmp_name = NULL; + } + + if (upper_sint_icmp_name) { + h_free(upper_sint_icmp_name); + upper_sint_icmp_name = NULL; + } + + if (upper_icmp_name) { + h_free(upper_icmp_name); + upper_icmp_name = NULL; + } + + if (rv_name) { + h_free(rv_name); + rv_name = NULL; + } + + return status; +} + +#endif + static const HParserVtable int_range_vt = { .parse = parse_int_range, .isValidRegular = h_true, .isValidCF = h_true, .desugar = desugar_int_range, .compile_to_rvm = ir_ctrvm, +#ifdef HAMMER_LLVM_BACKEND + .llvm = ir_llvm, +#endif .higher = false, }; diff --git a/src/t_parser.c b/src/t_parser.c index 52f815441896ee9dc2ef4e376821264b01732d6b..1c06fa9dfcfa9353eea323b0570e344a3836e50d 100644 --- a/src/t_parser.c +++ b/src/t_parser.c @@ -118,10 +118,40 @@ static void test_uint8(gconstpointer backend) { //@MARK_END static void test_int_range(gconstpointer backend) { - const HParser *int_range_ = h_int_range(h_uint8(), 3, 10); + const HParser *int_range_8_1_ = h_int_range(h_uint8(), 3, 10); + const HParser *int_range_8_2_ = h_int_range(h_int8(), -2, 5); + const HParser *int_range_8_3_ = h_int_range(h_int8(), 4, 12); + const HParser *int_range_8_4_ = h_int_range(h_int8(), -12, -3); + const HParser *int_range_16_1_ = h_int_range(h_uint16(), 3, 432); + const HParser *int_range_16_2_ = h_int_range(h_int16(), -22, 588); + const HParser *int_range_16_3_ = h_int_range(h_int16(), 129, 201); + const HParser *int_range_16_4_ = h_int_range(h_int16(), -301, -7); - g_check_parse_match(int_range_, (HParserBackend)GPOINTER_TO_INT(backend), "\x05", 1, "u0x5"); - g_check_parse_failed(int_range_, (HParserBackend)GPOINTER_TO_INT(backend), "\xb", 1); + g_check_parse_match(int_range_8_1_, (HParserBackend)GPOINTER_TO_INT(backend), "\x05", 1, "u0x5"); + g_check_parse_match(int_range_8_1_, (HParserBackend)GPOINTER_TO_INT(backend), "\x0a", 1, "u0xa"); + g_check_parse_match(int_range_8_1_, (HParserBackend)GPOINTER_TO_INT(backend), "\x03", 1, "u0x3"); + g_check_parse_failed(int_range_8_1_, (HParserBackend)GPOINTER_TO_INT(backend), "\xb", 1); + g_check_parse_failed(int_range_8_1_, (HParserBackend)GPOINTER_TO_INT(backend), "\x2", 1); + + g_check_parse_match(int_range_8_2_, (HParserBackend)GPOINTER_TO_INT(backend), "\x02", 1, "s0x2"); + g_check_parse_match(int_range_8_2_, (HParserBackend)GPOINTER_TO_INT(backend), "\x05", 1, "s0x5"); + g_check_parse_match(int_range_8_2_, (HParserBackend)GPOINTER_TO_INT(backend), "\xfe", 1, "s-0x2"); + g_check_parse_failed(int_range_8_2_, (HParserBackend)GPOINTER_TO_INT(backend), "\x7", 1); + g_check_parse_failed(int_range_8_2_, (HParserBackend)GPOINTER_TO_INT(backend), "\xfa", 1); + + g_check_parse_match(int_range_8_3_, (HParserBackend)GPOINTER_TO_INT(backend), "\x06", 1, "s0x6"); + g_check_parse_match(int_range_8_3_, (HParserBackend)GPOINTER_TO_INT(backend), "\x0c", 1, "s0xc"); + g_check_parse_match(int_range_8_3_, (HParserBackend)GPOINTER_TO_INT(backend), "\x04", 1, "s0x4"); + g_check_parse_failed(int_range_8_3_, (HParserBackend)GPOINTER_TO_INT(backend), "\x0f", 1); + g_check_parse_failed(int_range_8_3_, (HParserBackend)GPOINTER_TO_INT(backend), "\x03", 1); + g_check_parse_failed(int_range_8_3_, (HParserBackend)GPOINTER_TO_INT(backend), "\xfe", 1); + + g_check_parse_match(int_range_8_4_, (HParserBackend)GPOINTER_TO_INT(backend), "\xfb", 1, "s-0x5"); + g_check_parse_match(int_range_8_4_, (HParserBackend)GPOINTER_TO_INT(backend), "\xfd", 1, "s-0x3"); + g_check_parse_match(int_range_8_4_, (HParserBackend)GPOINTER_TO_INT(backend), "\xf4", 1, "s-0xc"); + g_check_parse_failed(int_range_8_4_, (HParserBackend)GPOINTER_TO_INT(backend), "\xff", 1); + g_check_parse_failed(int_range_8_4_, (HParserBackend)GPOINTER_TO_INT(backend), "\xf0", 1); + g_check_parse_failed(int_range_8_4_, (HParserBackend)GPOINTER_TO_INT(backend), "\x02", 1); } #if 0 @@ -1055,6 +1085,7 @@ void register_parser_tests(void) { g_test_add_data_func("/core/parser/llvm/uint32", GINT_TO_POINTER(PB_LLVM), test_uint32); g_test_add_data_func("/core/parser/llvm/uint16", GINT_TO_POINTER(PB_LLVM), test_uint16); g_test_add_data_func("/core/parser/llvm/uint8", GINT_TO_POINTER(PB_LLVM), test_uint8); + g_test_add_data_func("/core/parser/llvm/int_range", GINT_TO_POINTER(PB_LLVM), test_int_range); g_test_add_data_func("/core/parser/llvm/in", GINT_TO_POINTER(PB_LLVM), test_in); g_test_add_data_func("/core/parser/llvm/not_in", GINT_TO_POINTER(PB_LLVM), test_not_in); g_test_add_data_func("/core/parser/llvm/nothing_p", GINT_TO_POINTER(PB_LLVM), test_nothing_p);