issue #126 dmr_C now integral part of Ravi

pull/167/head
Dibyendu Majumdar 6 years ago
parent c2cd74143e
commit e10ab7b04f

@ -9,7 +9,6 @@ enable_testing()
# By default JIT is OFF
option(LLVM_JIT "Controls whether LLVM JIT compilation will be enabled, default is OFF" OFF)
option(STATIC_BUILD "Build static version of Ravi, default is OFF" OFF)
option(EMBEDDED_DMRC "Controls whether the embedded dmrC feature should be enabled, default is OFF" OFF)
option(COMPUTED_GOTO "Controls whether the interpreter switch will use computed gotos on gcc/clang, default is OFF" ON)
option(ASM_VM "Controls whether to use the new VM (not ready yet! so don't turn on)" OFF)
option(LTESTS "Controls whether ltests are enabled in Debug mode" ON)
@ -111,6 +110,8 @@ else()
endif ()
include_directories("${PROJECT_SOURCE_DIR}/include")
include_directories("${PROJECT_SOURCE_DIR}/dmr_c/src")
if (NOT LTESTS)
# Note that enabling ltests.h messes with global_State and thus interferes with ASM_VM
message(STATUS "Disabling Lua extended test harness 'ltests'")
@ -202,90 +203,85 @@ elseif (NOT WIN32)
set(EXTRA_LIBRARIES m dl readline)
endif ()
if (EMBEDDED_DMRC)
if (CMAKE_COMPILER_IS_GNUCC)
execute_process(COMMAND ${CMAKE_C_COMPILER} --print-file-name=
OUTPUT_VARIABLE GCC_BASE OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(COMMAND ${CMAKE_C_COMPILER} -print-multiarch
OUTPUT_VARIABLE MULTIARCH_TRIPLET ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
add_definitions(-DGCC_BASE="${GCC_BASE}")
add_definitions(-DMULTIARCH_TRIPLET="${MULTIARCH_TRIPLET}")
endif()
if (CMAKE_COMPILER_IS_GNUCC)
execute_process(COMMAND ${CMAKE_C_COMPILER} --print-file-name=
OUTPUT_VARIABLE GCC_BASE OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(COMMAND ${CMAKE_C_COMPILER} -print-multiarch
OUTPUT_VARIABLE MULTIARCH_TRIPLET ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
message( STATUS "GCC_BASE_DIR : " ${GCC_BASE})
message( STATUS "MULTIARCH_TRIPLET : " ${MULTIARCH_TRIPLET} )
include_directories("${PROJECT_SOURCE_DIR}/dmr_c/src")
set(DMR_C_HEADERS
dmr_c/src/allocate.h
dmr_c/src/char.h
dmr_c/src/expression.h
dmr_c/src/flow.h
dmr_c/src/ident-list.h
dmr_c/src/linearize.h
dmr_c/src/lib.h
dmr_c/src/parse.h
dmr_c/src/port.h
dmr_c/src/ptrlist.h
dmr_c/src/scope.h
dmr_c/src/symbol.h
dmr_c/src/target.h
dmr_c/src/token.h
dmr_c/src/walksymbol.h
)
add_definitions(-DGCC_BASE="${GCC_BASE}")
add_definitions(-DMULTIARCH_TRIPLET="${MULTIARCH_TRIPLET}")
endif()
set(DMR_C_SRCS
dmr_c/src/allocate.c
dmr_c/src/builtin.c
dmr_c/src/char.c
dmr_c/src/cse.c
dmr_c/src/expression.c
dmr_c/src/evaluate.c
dmr_c/src/expand.c
dmr_c/src/flow.c
dmr_c/src/inline.c
dmr_c/src/lib.c
dmr_c/src/linearize.c
dmr_c/src/liveness.c
dmr_c/src/memops.c
dmr_c/src/parse.c
dmr_c/src/target.c
dmr_c/src/tokenize.c
dmr_c/src/pre-process.c
dmr_c/src/ptrlist.c
dmr_c/src/scope.c
dmr_c/src/show-parse.c
dmr_c/src/simplify.c
dmr_c/src/symbol.c
dmr_c/src/unssa.c
dmr_c/src/walksymbol.c
src/ravi_dmrc_parsesymbols.c
)
message( STATUS "GCC_BASE_DIR : " ${GCC_BASE})
message( STATUS "MULTIARCH_TRIPLET : " ${MULTIARCH_TRIPLET} )
set(DMR_C_HEADERS
dmr_c/src/allocate.h
dmr_c/src/char.h
dmr_c/src/expression.h
dmr_c/src/flow.h
dmr_c/src/ident-list.h
dmr_c/src/linearize.h
dmr_c/src/lib.h
dmr_c/src/parse.h
dmr_c/src/port.h
dmr_c/src/ptrlist.h
dmr_c/src/scope.h
dmr_c/src/symbol.h
dmr_c/src/target.h
dmr_c/src/token.h
dmr_c/src/walksymbol.h
)
if (LLVM_JIT)
set(DMR_C_JIT_SRCS
dmr_c/llvm-backend/sparse-llvm.c
)
set(DMR_C_JIT_HEADERS
dmr_c/llvm-backend/dmr_c.h
)
include_directories("${PROJECT_SOURCE_DIR}/dmr_c/llvm-backend")
else()
set(DMR_C_JIT_HEADERS
dmr_c/null-backend/dmr_c.h
)
include_directories("${PROJECT_SOURCE_DIR}/dmr_c/null-backend")
endif()
set(DMR_C_SRCS
dmr_c/src/allocate.c
dmr_c/src/builtin.c
dmr_c/src/char.c
dmr_c/src/cse.c
dmr_c/src/expression.c
dmr_c/src/evaluate.c
dmr_c/src/expand.c
dmr_c/src/flow.c
dmr_c/src/inline.c
dmr_c/src/lib.c
dmr_c/src/linearize.c
dmr_c/src/liveness.c
dmr_c/src/memops.c
dmr_c/src/parse.c
dmr_c/src/target.c
dmr_c/src/tokenize.c
dmr_c/src/pre-process.c
dmr_c/src/ptrlist.c
dmr_c/src/scope.c
dmr_c/src/show-parse.c
dmr_c/src/simplify.c
dmr_c/src/symbol.c
dmr_c/src/unssa.c
dmr_c/src/walksymbol.c
src/ravi_dmrc_parsesymbols.c
)
if (LLVM_JIT)
set(DMR_C_JIT_SRCS
dmr_c/llvm-backend/sparse-llvm.c
)
set(DMR_C_JIT_HEADERS
dmr_c/llvm-backend/dmr_c.h
)
include_directories("${PROJECT_SOURCE_DIR}/dmr_c/llvm-backend")
else()
set(DMR_C_JIT_HEADERS
dmr_c/null-backend/dmr_c.h
)
include_directories("${PROJECT_SOURCE_DIR}/dmr_c/null-backend")
endif()
if (MSVC OR APPLE)
source_group("dmrC Headers" FILES ${DMR_C_HEADERS} ${DMR_C_JIT_HEADERS})
source_group("dmrC Source Files" FILES ${DMR_C_SRCS} ${DMR_C_JIT_SRCS})
endif()
if (MSVC OR APPLE)
source_group("dmrC Headers" FILES ${DMR_C_HEADERS} ${DMR_C_JIT_HEADERS})
source_group("dmrC Source Files" FILES ${DMR_C_SRCS} ${DMR_C_JIT_SRCS})
endif()
# Enable minimal required LLVM components so that the
# the size of the resulting binary is manageable
if (LLVM_JIT)
@ -394,6 +390,9 @@ set(NOJIT_RAVI_SRCS
${RAVI_HEADERS}
${LUA_LIB_SRCS}
${LUA_CORE_SRCS}
${DMR_C_HEADERS}
${DMR_C_SRCS}
${DMR_C_JIT_SRCS}
src/ravi_nojit.c)
# We always build a static library without JIT so that
@ -445,7 +444,6 @@ endif ()
add_test(TestVM test_vm)
add_test(TestMisc test_misc)
install(FILES ${LUA_HEADERS}
DESTINATION include/ravi)
install(TARGETS ${LIBRAVI_NAME} ravi ${RAVI_DEBUGGER_TARGET} ravi_s

@ -0,0 +1,44 @@
/**
* This is a backend code generator for dmr_C that uses
* the LLVM JIT engine.
*
* Copyright (C) 2017 Dibyendu Majumdar
*
* 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.
*/
#ifndef DMR_C_H
#define DMR_C_H
#include <llvm-c/Core.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
extern bool dmrC_llvmcompile(int argc, char **argv, LLVMModuleRef module,
const char *inputbuffer);
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

@ -0,0 +1,28 @@
/**
* This header is used when no backend is used
*
* Copyright (C) 2017 Dibyendu Majumdar
*
* 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.
*/
#ifndef DMR_C_H
#define DMR_C_H
#endif

@ -0,0 +1,67 @@
The code is organised as follows:
## Pointer Linked List
This is implemented in:
* ptrlist.h
* ptrlist.c
## Memory allocation
* allocate.h
* allocate.c
## Tokenizer
This is implemented in:
* token.h
* tokenize.c
The tokenizer depends on declarations in symbol.h and target.h
## Parser
The C parser parses code as well as evaluates constant expressions and as far as I can tell it will also perform
inlining of functions. The evaluation code is reused by the pre-processor so the C parser is lower level than the
pre-processor.
The parser implementation is in following:
* symbol.h
* symbol.c
* scope.h
* scope.c
* parse.h
* parse.c
* char.c
* char.h
* expression.h
* expression.c
* expand.c
* evaluate.c
* inline.c
* ident-list.h
* show-parse.c
## Pre-processor
The pre-processor depends upon the parser functions to evaluate expressions. It is implemented in:
* pre-process.c
## Linearizer
This component transforms the parsed representation to a linear form (SSA I believe). The implementation is in:
* linearize.h
* linearize.c
* flow.h
* flow.c
* cse.c
* liveness.c
* memops.c
* simplify.c
* unssa.c

@ -0,0 +1,214 @@
/*
* allocate.c - simple space-efficient blob allocator.
*
* Copyright (C) 2003 Transmeta Corp.
* 2003-2004 Linus Torvalds
*
* 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.
*
* Simple allocator for data that doesn't get partially free'd.
* The tokenizer and parser allocate a _lot_ of small data structures
* (often just two-three bytes for things like small integers),
* and since they all depend on each other you can't free them
* individually _anyway_. So do something that is very space-
* efficient: allocate larger "blobs", and give out individual
* small bits and pieces of it with no maintenance overhead.
*/
/*
* This version is part of the dmr_c project.
* Copyright (C) 2017 Dibyendu Majumdar
*/
#include <allocate.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void *dmrC_blob_alloc(size_t size) {
void *ptr;
ptr = malloc(size);
if (ptr != NULL)
memset(ptr, 0, size);
return ptr;
}
void dmrC_blob_free(void *addr, size_t size) {
(void)size;
free(addr);
}
void dmrC_allocator_init(struct allocator *A, const char *name, size_t size,
unsigned int alignment, unsigned int chunking) {
A->name_ = name;
A->blobs_ = NULL;
A->size_ = size;
A->alignment_ = alignment;
A->chunking_ = chunking;
A->freelist_ = NULL;
A->allocations = 0;
A->total_bytes = 0;
A->useful_bytes = 0;
}
void *dmrC_allocator_allocate(struct allocator *A, size_t extra) {
size_t size = extra + A->size_;
size_t alignment = A->alignment_;
struct allocation_blob *blob = A->blobs_;
void *retval;
assert(size <= A->chunking_);
/*
* NOTE! The freelist only works with things that are
* (a) sufficiently aligned
* (b) use a constant size
* Don't try to free allocators that don't follow
* these rules.
*/
if (A->freelist_) {
void **p = (void **)A->freelist_;
retval = p;
A->freelist_ = *p;
memset(retval, 0, size);
return retval;
}
A->allocations++;
A->useful_bytes += size;
size = (size + alignment - 1) & ~(alignment - 1);
if (!blob || blob->left < size) {
size_t offset, chunking = A->chunking_;
struct allocation_blob *newblob =
(struct allocation_blob *)dmrC_blob_alloc(chunking);
if (!newblob) {
fprintf(stderr, "out of memory\n");
abort();
}
A->total_bytes += chunking;
newblob->next = blob;
blob = newblob;
A->blobs_ = newblob;
offset = offsetof(struct allocation_blob, data);
offset = (offset + alignment - 1) & ~(alignment - 1);
blob->left = chunking - offset;
blob->offset = offset - offsetof(struct allocation_blob, data);
}
retval = blob->data + blob->offset;
blob->offset += size;
blob->left -= size;
return retval;
}
void dmrC_allocator_free(struct allocator *A, void *entry) {
void **p = (void **)entry;
*p = A->freelist_;
A->freelist_ = p;
}
void dmrC_allocator_show_allocations(struct allocator *A) {
fprintf(stderr, "%s: %d allocations, %d bytes (%d total bytes, "
"%6.2f%% usage, %6.2f average size)\n",
A->name_, (int)A->allocations, (int)A->useful_bytes,
(int)A->total_bytes, 100 * (double)A->useful_bytes / A->total_bytes,
(double)A->useful_bytes / A->allocations);
}
void dmrC_allocator_drop_all_allocations(struct allocator *A) {
struct allocation_blob *blob = A->blobs_;
A->blobs_ = NULL;
A->allocations = 0;
A->total_bytes = 0;
A->useful_bytes = 0;
A->freelist_ = NULL;
while (blob) {
struct allocation_blob *next = blob->next;
dmrC_blob_free(blob, A->chunking_);
blob = next;
}
}
void dmrC_allocator_destroy(struct allocator *A) {
dmrC_allocator_drop_all_allocations(A);
A->blobs_ = NULL;
A->allocations = 0;
A->total_bytes = 0;
A->useful_bytes = 0;
A->freelist_ = NULL;
}
void dmrC_allocator_transfer(struct allocator *A, struct allocator *transfer_to) {
assert(transfer_to->blobs_ == NULL);
assert(transfer_to->freelist_ == NULL);
transfer_to->blobs_ = A->blobs_;
transfer_to->allocations = A->allocations;
transfer_to->total_bytes = A->total_bytes;
transfer_to->useful_bytes = A->useful_bytes;
transfer_to->freelist_ = A->freelist_;
transfer_to->alignment_ = A->alignment_;
transfer_to->chunking_ = A->chunking_;
transfer_to->size_ = A->size_;
A->blobs_ = NULL;
A->allocations = 0;
A->total_bytes = 0;
A->useful_bytes = 0;
A->freelist_ = NULL;
}
struct foo {
int a, b;
};
int dmrC_test_allocator() {
struct allocator alloc;
dmrC_allocator_init(&alloc, "foo", sizeof(struct foo), __alignof__(struct foo),
sizeof(struct allocation_blob) + sizeof(struct foo) * 2);
struct foo *t1 = (struct foo *)dmrC_allocator_allocate(&alloc, 0);
if (t1 == NULL)
return 1;
if (alloc.alignment_ != __alignof__(struct foo))
return 1;
if (alloc.allocations != 1)
return 1;
if (alloc.freelist_ != NULL)
return 1;
struct foo *t2 = (struct foo *)dmrC_allocator_allocate(&alloc, 0);
if (t2 != t1 + 1)
return 1;
//dmrC_allocator_show_allocations(&alloc);
dmrC_allocator_free(&alloc, t1);
dmrC_allocator_free(&alloc, t2);
struct foo *t3 = (struct foo *)dmrC_allocator_allocate(&alloc, 0);
if (t3 != t2)
return 1;
struct foo *t4 = (struct foo *)dmrC_allocator_allocate(&alloc, 0);
if (t4 != t1)
return 1;
struct foo *t5 = (struct foo *)dmrC_allocator_allocate(&alloc, 0);
(void)t5;
if (alloc.total_bytes !=
(sizeof(struct allocation_blob) + sizeof(struct foo) * 2) * 2)
return 1;
struct allocator alloc2 = { 0 };
struct allocation_blob *saved = alloc.blobs_;
dmrC_allocator_transfer(&alloc, &alloc2);
if (alloc.blobs_ != NULL)
return 1;
if (alloc2.blobs_ != saved)
return 1;
dmrC_allocator_destroy(&alloc2);
printf("allocator tests okay\n");
return 0;
}

@ -0,0 +1,100 @@
#ifndef DMR_C_ALLOCATOR_H
#define DMR_C_ALLOCATOR_H
/*
* allocate.c - simple space-efficient blob allocator.
*
* Copyright (C) 2003 Transmeta Corp.
* 2003-2004 Linus Torvalds
*
* 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.
*
* Simple allocator for data that doesn't get partially free'd.
* The tokenizer and parser allocate a _lot_ of small data structures
* (often just two-three bytes for things like small integers),
* and since they all depend on each other you can't free them
* individually _anyway_. So do something that is very space-
* efficient: allocate larger "blobs", and give out individual
* small bits and pieces of it with no maintenance overhead.
*/
/*
* This version is part of the dmr_c project.
* Copyright (C) 2017 Dibyendu Majumdar
*/
#include <port.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
struct allocation_blob {
struct allocation_blob *next;
size_t left, offset;
unsigned char data[];
};
/*
* Our "blob" allocator works on chunks that are multiples
* of this size (the underlying allocator may be a mmap that
* cannot handle smaller chunks, for example, so trying to
* allocate blobs that aren't aligned is not going to work).
*/
#define CHUNK 32768
struct allocator {
const char *name_;
struct allocation_blob *blobs_;
size_t size_;
unsigned int alignment_;
unsigned int chunking_;
void *freelist_;
size_t allocations, total_bytes, useful_bytes;
};
extern void dmrC_allocator_init(struct allocator *A, const char *name, size_t size,
unsigned int alignment, unsigned int chunking);
extern void *dmrC_allocator_allocate(struct allocator *A, size_t extra);
extern void dmrC_allocator_free(struct allocator *A, void *entry);
extern void dmrC_allocator_show_allocations(struct allocator *A);
extern void dmrC_allocator_drop_all_allocations(struct allocator *A);
extern void dmrC_allocator_destroy(struct allocator *A);
extern void dmrC_allocator_transfer(struct allocator *A,
struct allocator *transfer_to);
extern int dmrC_test_allocator();
#ifdef __cplusplus
}
#endif
#endif

@ -0,0 +1,244 @@
/*
* builtin evaluation & expansion.
*
* Copyright (C) 2003 Transmeta Corp.
* 2003-2004 Linus Torvalds
*
* 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.
*/
#include <port.h>
#include <lib.h>
#include <expression.h>
#include <expand.h>
#include <symbol.h>
static int evaluate_to_integer(struct dmr_C *C, struct expression *expr)
{
expr->ctype = &C->S->int_ctype;
return 1;
}
static int evaluate_expect(struct dmr_C *C, struct expression *expr)
{
/* Should we evaluate it to return the type of the first argument? */
expr->ctype = &C->S->int_ctype;
return 1;
}
static int arguments_choose(struct dmr_C *C, struct expression *expr)
{
struct expression_list *arglist = expr->args;
struct expression *arg;
int i = 0;
FOR_EACH_PTR (arglist, arg) {
if (!dmrC_evaluate_expression(C, arg))
return 0;
i++;
} END_FOR_EACH_PTR(arg);
if (i < 3) {
dmrC_sparse_error(C, expr->pos,
"not enough arguments for __builtin_choose_expr");
return 0;
} if (i > 3) {
dmrC_sparse_error(C, expr->pos,
"too many arguments for __builtin_choose_expr");
return 0;
}
return 1;
}
static int evaluate_choose(struct dmr_C *C, struct expression *expr)
{
struct expression_list *list = expr->args;
struct expression *arg, *args[3];
int n = 0;
/* there will be exactly 3; we'd already verified that */
FOR_EACH_PTR(list, arg) {
args[n++] = arg;
} END_FOR_EACH_PTR(arg);
*expr = dmrC_get_expression_value(C, args[0]) ? *args[1] : *args[2];
return 1;
}
static int expand_expect(struct dmr_C *C, struct expression *expr, int cost)
{
struct expression *arg = dmrC_first_expression(expr->args);
if (arg)
*expr = *arg;
return 0;
}
/*
* __builtin_warning() has type "int" and always returns 1,
* so that you can use it in conditionals or whatever
*/
static int expand_warning(struct dmr_C *C, struct expression *expr, int cost)
{
struct expression *arg;
struct expression_list *arglist = expr->args;
FOR_EACH_PTR (arglist, arg) {
/*
* Constant strings get printed out as a warning. By the
* time we get here, the EXPR_STRING has been fully
* evaluated, so by now it's an anonymous symbol with a
* string initializer.
*
* Just for the heck of it, allow any constant string
* symbol.
*/
if (arg->type == EXPR_SYMBOL) {
struct symbol *sym = arg->symbol;
if (sym->initializer && sym->initializer->type == EXPR_STRING) {
struct string *string = sym->initializer->string;
dmrC_warning(C, expr->pos, "%*s", string->length-1, string->data);
}
continue;
}
/*
* Any other argument is a conditional. If it's
* non-constant, or it is false, we exit and do
* not print any warning.
*/
if (arg->type != EXPR_VALUE)
goto out;
if (!arg->value)
goto out;
} END_FOR_EACH_PTR(arg);
out:
expr->type = EXPR_VALUE;
expr->value = 1;
expr->taint = 0;
return 0;
}
/* The arguments are constant if the cost of all of them is zero */
static int expand_constant_p(struct dmr_C *C, struct expression *expr, int cost)
{
expr->type = EXPR_VALUE;
expr->value = !cost;
expr->taint = 0;
return 0;
}
/* The arguments are safe, if their cost is less than SIDE_EFFECTS */
static int expand_safe_p(struct dmr_C *C, struct expression *expr, int cost)
{
expr->type = EXPR_VALUE;
expr->value = (cost < SIDE_EFFECTS);
expr->taint = 0;
return 0;
}
static struct symbol_op constant_p_op = {
.evaluate = evaluate_to_integer,
.expand = expand_constant_p
};
static struct symbol_op safe_p_op = {
.evaluate = evaluate_to_integer,
.expand = expand_safe_p
};
static struct symbol_op warning_op = {
.evaluate = evaluate_to_integer,
.expand = expand_warning
};
static struct symbol_op expect_op = {
.evaluate = evaluate_expect,
.expand = expand_expect
};
static struct symbol_op choose_op = {
.evaluate = evaluate_choose,
.args = arguments_choose,
};
/* The argument is constant and valid if the cost is zero */
static int expand_bswap(struct dmr_C *C, struct expression *expr, int cost)
{
struct expression *arg;
long long val;
if (cost)
return cost;
/* the arguments number & type have already been checked */
arg = dmrC_first_expression(expr->args);
val = dmrC_get_expression_value_silent(C, arg);
switch (expr->ctype->bit_size) {
case 16: expr->value = __builtin_bswap16(val); break;
case 32: expr->value = __builtin_bswap32(val); break;
case 64: expr->value = __builtin_bswap64(val); break;
default: /* impossible error */
return SIDE_EFFECTS;
}
expr->type = EXPR_VALUE;
expr->taint = 0;
return 0;
}
static struct symbol_op bswap_op = {
.expand = expand_bswap,
};
/*
* Builtin functions
*/
static struct symbol builtin_fn_type = { .type = SYM_FN /* , .variadic =1 */ };
static struct sym_init {
const char *name;
struct symbol *base_type;
unsigned int modifiers;
struct symbol_op *op;
} builtins_table[] = {
{ "__builtin_constant_p", &builtin_fn_type, MOD_TOPLEVEL, &constant_p_op },
{ "__builtin_safe_p", &builtin_fn_type, MOD_TOPLEVEL, &safe_p_op },
{ "__builtin_warning", &builtin_fn_type, MOD_TOPLEVEL, &warning_op },
{ "__builtin_expect", &builtin_fn_type, MOD_TOPLEVEL, &expect_op },
{ "__builtin_choose_expr", &builtin_fn_type, MOD_TOPLEVEL, &choose_op },
{ "__builtin_bswap16", NULL, MOD_TOPLEVEL, &bswap_op },
{ "__builtin_bswap32", NULL, MOD_TOPLEVEL, &bswap_op },
{ "__builtin_bswap64", NULL, MOD_TOPLEVEL, &bswap_op },
{ NULL, NULL, 0 }
};
void dmrC_init_builtins(struct dmr_C *C, int stream)
{
struct sym_init *ptr;
builtin_fn_type.variadic = 1;
for (ptr = builtins_table; ptr->name; ptr++) {
struct symbol *sym;
sym = dmrC_create_symbol(C->S, stream, ptr->name, SYM_NODE, NS_SYMBOL);
sym->ctype.base_type = ptr->base_type;
sym->ctype.modifiers = ptr->modifiers;
sym->op = ptr->op;
}
}

@ -0,0 +1,181 @@
/*
* sparse/char.c
*
* Copyright (C) 2003 Transmeta Corp.
* 2003-2004 Linus Torvalds
*
* 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.
*/
/*
* This version is part of the dmr_c project.
* Copyright (C) 2017 Dibyendu Majumdar
*/
#include <string.h>
#include <port.h>
#include <target.h>
#include <lib.h>
#include <allocate.h>
#include <token.h>
#include <expression.h>
static const char *parse_escape(struct dmr_C *C, const char *p, unsigned *val, const char *end, int bits, struct position pos)
{
unsigned c = *p++;
unsigned d;
if (c != '\\') {
*val = c;
return p;
}
c = *p++;
switch (c) {
case 'a': c = '\a'; break;
case 'b': c = '\b'; break;
case 't': c = '\t'; break;
case 'n': c = '\n'; break;
case 'v': c = '\v'; break;
case 'f': c = '\f'; break;
case 'r': c = '\r'; break;
#ifndef _MSC_VER
case 'e': c = '\e'; break;
#endif
case 'x': {
unsigned mask = -(1U << (bits - 4));
for (c = 0; p < end; c = (c << 4) + d) {
d = dmrC_hexval(*p);
if (d > 16)
break;
p++;
if (c & mask) {
dmrC_warning(C, pos,
"hex escape sequence out of range");
mask = 0;
}
}
break;
}
case '0':case '1': case '2': case '3': case '4': case '5':
case '6': case '7': {
if (p + 2 < end)
end = p + 2;
c -= '0';
while (p < end && (d = *p - '0') < 8) {
c = (c << 3) + d;
p++;
}
if ((c & 0400) && bits < 9)
dmrC_warning(C, pos,
"octal escape sequence out of range");
break;
}
default: /* everything else is left as is */
dmrC_warning(C, pos, "unknown escape sequence: '\\%c'", c);
break;
case '\\':
case '\'':
case '"':
case '?':
break; /* those are legal, so no warnings */
}
*val = c & ~((~0U << (bits - 1)) << 1);
return p;
}
void dmrC_get_char_constant(struct dmr_C *C, struct token *token, unsigned long long *val)
{
const char *p = token->embedded, *end;
unsigned v;
int type = dmrC_token_type(token);
switch (type) {
case TOKEN_CHAR:
case TOKEN_WIDE_CHAR:
p = token->string->data;
end = p + token->string->length - 1;
break;
case TOKEN_CHAR_EMBEDDED_0:
case TOKEN_CHAR_EMBEDDED_1:
case TOKEN_CHAR_EMBEDDED_2:
case TOKEN_CHAR_EMBEDDED_3:
end = p + type - TOKEN_CHAR;
break;
default:
end = p + type - TOKEN_WIDE_CHAR;
}
p = parse_escape(C, p, &v, end,
type < TOKEN_WIDE_CHAR ? C->target->bits_in_char : C->target->bits_in_wchar, token->pos);
if (p != end)
dmrC_warning(C, token->pos,
"multi-character character constant");
*val = v;
}
struct token *dmrC_get_string_constant(struct dmr_C *C, struct token *token, struct expression *expr)
{
struct string *string = token->string;
struct token *next = token->next, *done = NULL;
int stringtype = dmrC_token_type(token);
int is_wide = stringtype == TOKEN_WIDE_STRING;
char buffer[MAX_STRING];
int len = 0;
int bits;
int esc_count = 0;
while (!done) {
switch (dmrC_token_type(next)) {
case TOKEN_WIDE_STRING:
is_wide = 1;
case TOKEN_STRING:
next = next->next;
break;
default:
done = next;
}
}
bits = is_wide ? C->target->bits_in_wchar : C->target->bits_in_char;
while (token != done) {
unsigned v;
const char *p = token->string->data;
const char *end = p + token->string->length - 1;
while (p < end) {
if (*p == '\\')
esc_count++;
p = parse_escape(C, p, &v, end, bits, token->pos);
if (len < MAX_STRING)
buffer[len] = v;
len++;
}
token = token->next;
}
if (len > MAX_STRING) {
dmrC_warning(C, token->pos, "trying to concatenate %d-character string (%d bytes max)", len, MAX_STRING);
len = MAX_STRING;
}
if (esc_count || len >= (int)string->length) {
if (string->immutable || len >= string->length) /* can't cannibalize */
string = (struct string *)dmrC_allocator_allocate(&C->string_allocator, len+1);
string->length = len+1;
memcpy(string->data, buffer, len);
string->data[len] = '\0';
}
expr->string = string;
expr->wide = is_wide;
return token;
}

@ -0,0 +1,25 @@
/*
* sparse/char.h
*
* Copyright (C) 2003 Transmeta Corp.
* 2003 Linus Torvalds
*
* This version is part of the dmr_c project.
* Copyright (C) 2017 Dibyendu Majumdar
*/
#ifndef DMR_C_CHAR_H
#define DMR_C_CHAR_H
#ifdef __cplusplus
extern "C" {
#endif
extern void dmrC_get_char_constant(struct dmr_C *C, struct token *, unsigned long long *);
extern struct token *dmrC_get_string_constant(struct dmr_C *C, struct token *, struct expression *);
#ifdef __cplusplus
}
#endif
#endif

@ -0,0 +1,393 @@
/*
* CSE - walk the linearized instruction flow, and
* see if we can simplify it and apply CSE on it.
*
* Copyright (C) 2004 Linus Torvalds
*/
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <assert.h>
#include <port.h>
#include <parse.h>
#include <expression.h>
#include <linearize.h>
#include <flow.h>
static int phi_compare(pseudo_t phi1, pseudo_t phi2)
{
const struct instruction *def1 = phi1->def;
const struct instruction *def2 = phi2->def;
if (def1->src1 != def2->src1)
return def1->src1 < def2->src1 ? -1 : 1;
if (def1->bb != def2->bb)
return def1->bb < def2->bb ? -1 : 1;
return 0;
}
static void clean_up_one_instruction(struct dmr_C *C, struct basic_block *bb, struct instruction *insn)
{
unsigned long hash;
if (!insn->bb)
return;
assert(insn->bb == bb);
C->L->repeat_phase |= dmrC_simplify_instruction(C, insn);
if (!insn->bb)
return;
hash = (insn->opcode << 3) + (insn->size >> 3);
switch (insn->opcode) {
case OP_SEL:
hash += dmrC_hashval(insn->src3);
/* Fall through */
/* Binary arithmetic */
case OP_ADD: case OP_SUB:
case OP_MULU: case OP_MULS:
case OP_DIVU: case OP_DIVS:
case OP_MODU: case OP_MODS:
case OP_SHL:
case OP_LSR: case OP_ASR:
case OP_AND: case OP_OR:
/* Binary logical */
case OP_XOR: case OP_AND_BOOL:
case OP_OR_BOOL:
/* Binary comparison */
case OP_SET_EQ: case OP_SET_NE:
case OP_SET_LE: case OP_SET_GE:
case OP_SET_LT: case OP_SET_GT:
case OP_SET_B: case OP_SET_A:
case OP_SET_BE: case OP_SET_AE:
hash += dmrC_hashval(insn->src2);
/* Fall through */
/* Unary */
case OP_NOT: case OP_NEG:
hash += dmrC_hashval(insn->src1);
break;
case OP_SETVAL:
hash += dmrC_hashval(insn->val);
break;
case OP_SYMADDR:
hash += dmrC_hashval(insn->symbol);
break;
case OP_CAST:
case OP_SCAST:
case OP_PTRCAST:
/*
* This is crap! Many "orig_types" are the
* same as far as casts go, we should generate
* some kind of "type hash" that is identical
* for identical casts
*/
hash += dmrC_hashval(insn->orig_type);
hash += dmrC_hashval(insn->src);
break;
/* Other */
case OP_PHI: {
pseudo_t phi;
FOR_EACH_PTR(insn->phi_list, phi) {
struct instruction *def;
if (phi == VOID_PSEUDO(C) || !phi->def)
continue;
def = phi->def;
hash += dmrC_hashval(def->src1);
hash += dmrC_hashval(def->bb);
} END_FOR_EACH_PTR(phi);
break;
}
default:
/*
* Nothing to do, don't even bother hashing them,
* we're not going to try to CSE them
*/
return;
}
hash += hash >> 16;
hash &= INSN_HASH_SIZE-1;
dmrC_add_instruction(C, C->L->insn_hash_table + hash, insn);
}
static void clean_up_insns(struct dmr_C *C, struct entrypoint *ep)
{
struct basic_block *bb;
FOR_EACH_PTR(ep->bbs, bb) {
struct instruction *insn;
FOR_EACH_PTR(bb->insns, insn) {
clean_up_one_instruction(C, bb, insn);
} END_FOR_EACH_PTR(insn);
} END_FOR_EACH_PTR(bb);
}
/* Compare two (sorted) phi-lists */
static int phi_list_compare(struct dmr_C *C, struct pseudo_list *l1, struct pseudo_list *l2)
{
pseudo_t phi1, phi2;
PREPARE_PTR_LIST(l1, phi1);
PREPARE_PTR_LIST(l2, phi2);
for (;;) {
int cmp;
while (phi1 && (phi1 == VOID_PSEUDO(C) || !phi1->def))
NEXT_PTR_LIST(phi1);
while (phi2 && (phi2 == VOID_PSEUDO(C) || !phi2->def))
NEXT_PTR_LIST(phi2);
if (!phi1)
return phi2 ? -1 : 0;
if (!phi2)
return phi1 ? 1 : 0;
cmp = phi_compare(phi1, phi2);
if (cmp)
return cmp;
NEXT_PTR_LIST(phi1);
NEXT_PTR_LIST(phi2);
}
/* Not reached, but we need to make the nesting come out right */
FINISH_PTR_LIST(phi2);
FINISH_PTR_LIST(phi1);
}
static int insn_compare(void *ud, const void *_i1, const void *_i2)
{
struct dmr_C *C = (struct dmr_C *) ud;
const struct instruction *i1 = _i1;
const struct instruction *i2 = _i2;
if (i1->opcode != i2->opcode)
return i1->opcode < i2->opcode ? -1 : 1;
switch (i1->opcode) {
/* commutative binop */
case OP_ADD:
case OP_MULU: case OP_MULS:
case OP_AND_BOOL: case OP_OR_BOOL:
case OP_AND: case OP_OR:
case OP_XOR:
case OP_SET_EQ: case OP_SET_NE:
if (i1->src1 == i2->src2 && i1->src2 == i2->src1)
return 0;
goto case_binops;
case OP_SEL:
if (i1->src3 != i2->src3)
return i1->src3 < i2->src3 ? -1 : 1;
/* Fall-through to binops */
/* Binary arithmetic */
case OP_SUB:
case OP_DIVU: case OP_DIVS:
case OP_MODU: case OP_MODS:
case OP_SHL:
case OP_LSR: case OP_ASR:
/* Binary comparison */
case OP_SET_LE: case OP_SET_GE:
case OP_SET_LT: case OP_SET_GT:
case OP_SET_B: case OP_SET_A:
case OP_SET_BE: case OP_SET_AE:
case_binops:
if (i1->src2 != i2->src2)
return i1->src2 < i2->src2 ? -1 : 1;
/* Fall through to unops */
/* Unary */
case OP_NOT: case OP_NEG:
if (i1->src1 != i2->src1)
return i1->src1 < i2->src1 ? -1 : 1;
break;
case OP_SYMADDR:
if (i1->symbol != i2->symbol)
return i1->symbol < i2->symbol ? -1 : 1;
break;
case OP_SETVAL:
if (i1->val != i2->val)
return i1->val < i2->val ? -1 : 1;
break;
/* Other */
case OP_PHI:
return phi_list_compare(C, i1->phi_list, i2->phi_list);
case OP_CAST:
case OP_SCAST:
case OP_PTRCAST:
/*
* This is crap! See the comments on hashing.
*/
if (i1->orig_type != i2->orig_type)
return i1->orig_type < i2->orig_type ? -1 : 1;
if (i1->src != i2->src)
return i1->src < i2->src ? -1 : 1;
break;
default:
dmrC_warning(C, i1->pos, "bad instruction on hash chain");
}
if (i1->size != i2->size)
return i1->size < i2->size ? -1 : 1;
return 0;
}
static void sort_instruction_list(struct dmr_C *C, struct instruction_list **list)
{
ptrlist_sort((struct ptr_list **)list, C, insn_compare);
}
static struct instruction * cse_one_instruction(struct dmr_C *C, struct instruction *insn, struct instruction *def)
{
dmrC_convert_instruction_target(C, insn, def->target);
dmrC_kill_instruction(C, insn);
C->L->repeat_phase |= REPEAT_CSE;
return def;
}
/*
* Does "bb1" dominate "bb2"?
*/
static int bb_dominates(struct entrypoint *ep, struct basic_block *bb1, struct basic_block *bb2, unsigned long generation)
{
struct basic_block *parent;
/* Nothing dominates the entrypoint.. */
if (bb2 == ep->entry->bb)
return 0;
FOR_EACH_PTR(bb2->parents, parent) {
if (parent == bb1)
continue;
if (parent->generation == generation)
continue;
parent->generation = generation;
if (!bb_dominates(ep, bb1, parent, generation))
return 0;
} END_FOR_EACH_PTR(parent);
return 1;
}
static struct basic_block *trivial_common_parent(struct basic_block *bb1, struct basic_block *bb2)
{
struct basic_block *parent;
if (dmrC_bb_list_size(bb1->parents) != 1)
return NULL;
parent = dmrC_first_basic_block(bb1->parents);
if (dmrC_bb_list_size(bb2->parents) != 1)
return NULL;
if (dmrC_first_basic_block(bb2->parents) != parent)
return NULL;
return parent;
}
static inline void remove_instruction(struct instruction_list **list, struct instruction *insn, int count)
{
ptrlist_remove((struct ptr_list **)list, insn, count);
}
static void add_instruction_to_end(struct dmr_C *C, struct instruction *insn, struct basic_block *bb)
{
struct instruction *br = dmrC_delete_last_instruction(&bb->insns);
insn->bb = bb;
dmrC_add_instruction(C, &bb->insns, insn);
dmrC_add_instruction(C, &bb->insns, br);
}
static struct instruction * try_to_cse(struct dmr_C *C, struct entrypoint *ep, struct instruction *i1, struct instruction *i2)
{
struct basic_block *b1, *b2, *common;
/*
* OK, i1 and i2 are the same instruction, modulo "target".
* We should now see if we can combine them.
*/
b1 = i1->bb;
b2 = i2->bb;
/*
* Currently we only handle the uninteresting degenerate case where
* the CSE is inside one basic-block.
*/
if (b1 == b2) {
struct instruction *insn;
FOR_EACH_PTR(b1->insns, insn) {
if (insn == i1)
return cse_one_instruction(C, i2, i1);
if (insn == i2)
return cse_one_instruction(C, i1, i2);
} END_FOR_EACH_PTR(insn);
dmrC_warning(C, b1->pos, "Whaa? unable to find CSE instructions");
return i1;
}
if (bb_dominates(ep, b1, b2, ++C->L->bb_generation))
return cse_one_instruction(C, i2, i1);
if (bb_dominates(ep, b2, b1, ++C->L->bb_generation))
return cse_one_instruction(C, i1, i2);
/* No direct dominance - but we could try to find a common ancestor.. */
common = trivial_common_parent(b1, b2);
if (common) {
i1 = cse_one_instruction(C, i2, i1);
remove_instruction(&b1->insns, i1, 1);
add_instruction_to_end(C, i1, common);
}
return i1;
}
void dmrC_cleanup_and_cse(struct dmr_C *C, struct entrypoint *ep)
{
int i;
dmrC_simplify_memops(C, ep);
repeat:
C->L->repeat_phase = 0;
clean_up_insns(C, ep);
if (C->L->repeat_phase & REPEAT_CFG_CLEANUP)
dmrC_kill_unreachable_bbs(C, ep);
for (i = 0; i < INSN_HASH_SIZE; i++) {
struct instruction_list **list = C->L->insn_hash_table + i;
if (*list) {
if (dmrC_instruction_list_size(*list) > 1) {
struct instruction *insn, *last;
sort_instruction_list(C, list);
last = NULL;
FOR_EACH_PTR(*list, insn) {
if (!insn->bb)
continue;
if (last) {
if (!insn_compare(C, last, insn))
insn = try_to_cse(C, ep, last, insn);
}
last = insn;
} END_FOR_EACH_PTR(insn);
}
ptrlist_remove_all((struct ptr_list **)list);
}
}
if (C->L->repeat_phase & REPEAT_SYMBOL_CLEANUP)
dmrC_simplify_memops(C, ep);
if (C->L->repeat_phase & REPEAT_CSE)
goto repeat;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,34 @@
#ifndef EXPAND_H
#define EXPAND_H
/*
* sparse/expand.h
*
* Copyright (C) 2003 Transmeta Corp.
* 2003 Linus Torvalds
*
* 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.
*/
/* Random cost numbers */
#define SIDE_EFFECTS 10000 /* The expression has side effects */
#define UNSAFE 100 /* The expression may be "infinitely costly" due to exceptions */
#define SELECT_COST 20 /* Cut-off for turning a conditional into a select */
#define BRANCH_COST 10 /* Cost of a conditional branch */
#endif

@ -0,0 +1,930 @@
/*
* sparse/expression.c
*
* Copyright (C) 2003 Transmeta Corp.
* 2003-2004 Linus Torvalds
*
* 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.
*
* This is the expression parsing part of parsing C.
*/
/*
* This version is part of the dmr_c project.
* Copyright (C) 2017 Dibyendu Majumdar
*/
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <errno.h>
#include <limits.h>
#include <port.h>
#include <lib.h>
#include <allocate.h>
#include <token.h>
#include <parse.h>
#include <symbol.h>
#include <scope.h>
#include <expression.h>
#include <target.h>
#include <char.h>
static int match_oplist(int op, ...)
{
va_list args;
int nextop;
va_start(args, op);
do {
nextop = va_arg(args, int);
} while (nextop != 0 && nextop != op);
va_end(args);
return nextop != 0;
}
static struct token *comma_expression(struct dmr_C *C, struct token *, struct expression **);
struct token *dmrC_parens_expression(struct dmr_C *C, struct token *token, struct expression **expr, const char *where)
{
token = dmrC_expect_token(C, token, '(', where);
if (dmrC_match_op(token, '{')) {
struct expression *e = dmrC_alloc_expression(C, token->pos, EXPR_STATEMENT);
struct statement *stmt = dmrC_alloc_statement(C, token->pos, STMT_COMPOUND);
*expr = e;
e->statement = stmt;
dmrC_start_symbol_scope(C);
token = dmrC_compound_statement(C, token->next, stmt);
dmrC_end_symbol_scope(C);
token = dmrC_expect_token(C, token, '}', "at end of statement expression");
} else
token = dmrC_parse_expression(C, token, expr);
return dmrC_expect_token(C, token, ')', where);
}
/*
* Handle __func__, __FUNCTION__ and __PRETTY_FUNCTION__ token
* conversion
*/
static struct symbol *handle_func(struct dmr_C *C, struct token *token)
{
struct ident *ident = token->ident;
struct symbol *decl, *array;
struct string *string;
int len;
if (ident != C->S->__func___ident &&
ident != C->S->__FUNCTION___ident &&
ident != C->S->__PRETTY_FUNCTION___ident)
return NULL;
if (!C->current_fn || !C->current_fn->ident)
return NULL;
/* OK, it's one of ours */
array = dmrC_alloc_symbol(C->S, token->pos, SYM_ARRAY);
array->ctype.base_type = &C->S->char_ctype;
array->ctype.alignment = 1;
array->endpos = token->pos;
decl = dmrC_alloc_symbol(C->S, token->pos, SYM_NODE);
decl->ctype.base_type = array;
decl->ctype.alignment = 1;
decl->ctype.modifiers = MOD_STATIC;
decl->endpos = token->pos;
/* function-scope, but in NS_SYMBOL */
dmrC_bind_symbol(C->S, decl, ident, NS_LABEL);
decl->ns = NS_SYMBOL;
len = C->current_fn->ident->len;
string = (struct string *)dmrC_allocator_allocate(&C->string_allocator, len + 1);
memcpy(string->data, C->current_fn->ident->name, len);
string->data[len] = 0;
string->length = len + 1;
decl->initializer = dmrC_alloc_expression(C, token->pos, EXPR_STRING);
decl->initializer->string = string;
decl->initializer->ctype = decl;
decl->array_size = dmrC_alloc_const_expression(C, token->pos, len + 1);
array->array_size = decl->array_size;
decl->bit_size = array->bit_size = dmrC_bytes_to_bits(C->target, len + 1);
return decl;
}
static struct token *parse_type(struct dmr_C *C, struct token *token, struct expression **tree)
{
struct symbol *sym;
*tree = dmrC_alloc_expression(C, token->pos, EXPR_TYPE);
(*tree)->flags = Int_const_expr; /* sic */
token = dmrC_typename(C, token, &sym, NULL);
if (sym->ident)
dmrC_sparse_error(C, token->pos,
"type expression should not include identifier "
"\"%s\"", sym->ident->name);
(*tree)->symbol = sym;
return token;
}
static struct token *builtin_types_compatible_p_expr(struct dmr_C *C, struct token *token,
struct expression **tree)
{
struct expression *expr = dmrC_alloc_expression(
C, token->pos, EXPR_COMPARE);
expr->flags = Int_const_expr;
expr->op = SPECIAL_EQUAL;
token = token->next;
if (!dmrC_match_op(token, '('))
return dmrC_expect_token(C, token, '(',
"after __builtin_types_compatible_p");
token = token->next;
token = parse_type(C, token, &expr->left);
if (!dmrC_match_op(token, ','))
return dmrC_expect_token(C, token, ',',
"in __builtin_types_compatible_p");
token = token->next;
token = parse_type(C, token, &expr->right);
if (!dmrC_match_op(token, ')'))
return dmrC_expect_token(C, token, ')',
"at end of __builtin_types_compatible_p");
token = token->next;
*tree = expr;
return token;
}
static struct token *builtin_offsetof_expr(struct dmr_C *C, struct token *token,
struct expression **tree)
{
struct expression *expr = NULL;
struct expression **p = &expr;
struct symbol *sym;
int op = '.';
token = token->next;
if (!dmrC_match_op(token, '('))
return dmrC_expect_token(C, token, '(', "after __builtin_offset");
token = token->next;
token = dmrC_typename(C, token, &sym, NULL);
if (sym->ident)
dmrC_sparse_error(C, token->pos,
"type expression should not include identifier "
"\"%s\"", sym->ident->name);
if (!dmrC_match_op(token, ','))
return dmrC_expect_token(C, token, ',', "in __builtin_offset");
while (1) {
struct expression *e;
switch (op) {
case ')':
expr->in = sym;
*tree = expr;
default:
return dmrC_expect_token(C, token, ')', "at end of __builtin_offset");
case SPECIAL_DEREFERENCE:
e = dmrC_alloc_expression(C, token->pos, EXPR_OFFSETOF);
e->flags = Int_const_expr;
e->op = '[';
*p = e;
p = &e->down;
/* fall through */
case '.':
token = token->next;
e = dmrC_alloc_expression(C, token->pos, EXPR_OFFSETOF);
e->flags = Int_const_expr;
e->op = '.';
if (dmrC_token_type(token) != TOKEN_IDENT) {
dmrC_sparse_error(C, token->pos, "Expected member name");
return token;
}
e->ident = token->ident;
token = token->next;
break;
case '[':
token = token->next;
e = dmrC_alloc_expression(C, token->pos, EXPR_OFFSETOF);
e->flags = Int_const_expr;
e->op = '[';
token = dmrC_parse_expression(C, token, &e->index);
token = dmrC_expect_token(C, token, ']',
"at end of array dereference");
if (!e->index)
return token;
}
*p = e;
p = &e->down;
op = dmrC_token_type(token) == TOKEN_SPECIAL ? token->special : 0;
}
}
#ifndef ULLONG_MAX
#define ULLONG_MAX (~0ULL)
#endif
static unsigned long long parse_num(const char *nptr, char **end)
{
if (nptr[0] == '0' && tolower((unsigned char)nptr[1]) == 'b')
return strtoull(&nptr[2], end, 2);
return strtoull(nptr, end, 0);
}
static void get_number_value(struct dmr_C *C, struct expression *expr, struct token *token)
{
const char *str = token->number;
unsigned long long value;
char *end;
int size = 0, want_unsigned = 0;
int overflow = 0, do_warn = 0;
int try_unsigned = 1;
int bits;
errno = 0;
value = parse_num(str, &end);
if (end == str)
goto Float;
if (value == ULLONG_MAX && errno == ERANGE)
overflow = 1;
while (1) {
char c = *end++;
if (!c) {
break;
} else if (c == 'u' || c == 'U') {
if (want_unsigned)
goto Enoint;
want_unsigned = 1;
} else if (c == 'l' || c == 'L') {
if (size)
goto Enoint;
size = 1;
if (*end == c) {
size = 2;
end++;
}
} else
goto Float;
}
if (overflow)
goto Eoverflow;
/* OK, it's a valid integer */
/* decimals can be unsigned only if directly specified as such */
if (str[0] != '0' && !want_unsigned)
try_unsigned = 0;
if (!size) {
bits = C->target->bits_in_int - 1;
if (!(value & (~1ULL << bits))) {
if (!(value & (1ULL << bits))) {
goto got_it;
} else if (try_unsigned) {
want_unsigned = 1;
goto got_it;
}
}
size = 1;
do_warn = 1;
}
if (size < 2) {
bits = C->target->bits_in_long - 1;
if (!(value & (~1ULL << bits))) {
if (!(value & (1ULL << bits))) {
goto got_it;
} else if (try_unsigned) {
want_unsigned = 1;
goto got_it;
}
do_warn |= 2;
}
size = 2;
do_warn |= 1;
}
bits = C->target->bits_in_longlong - 1;
if (value & (~1ULL << bits))
goto Eoverflow;
if (!(value & (1ULL << bits)))
goto got_it;
if (!try_unsigned)
dmrC_warning(C, expr->pos, "decimal constant %s is too big for long long",
dmrC_show_token(C, token));
want_unsigned = 1;
got_it:
if (do_warn)
dmrC_warning(C, expr->pos, "constant %s is so big it is%s%s%s",
dmrC_show_token(C, token),
want_unsigned ? " unsigned":"",
size > 0 ? " long":"",
size > 1 ? " long":"");
if (do_warn & 2)
dmrC_warning(C, expr->pos,
"decimal constant %s is between LONG_MAX and ULONG_MAX."
" For C99 that means long long, C90 compilers are very "
"likely to produce unsigned long (and a warning) here",
dmrC_show_token(C, token));
expr->type = EXPR_VALUE;
expr->flags = Int_const_expr;
expr->ctype = dmrC_ctype_integer(C, size, want_unsigned);
expr->value = value;
return;
Eoverflow:
dmrC_error_die(C, expr->pos, "constant %s is too big even for unsigned long long",
dmrC_show_token(C, token));
return;
Float:
expr->fvalue = dmrC_string_to_ld(str, &end);
if (str == end)
goto Enoint;
if (*end && end[1])
goto Enoint;
if (*end == 'f' || *end == 'F')
expr->ctype = &C->S->float_ctype;
else if (*end == 'l' || *end == 'L')
expr->ctype = &C->S->ldouble_ctype;
else if (!*end)
expr->ctype = &C->S->double_ctype;
else
goto Enoint;
expr->flags = Float_literal;
expr->type = EXPR_FVALUE;
return;
Enoint:
dmrC_error_die(C, expr->pos, "constant %s is not a valid number", dmrC_show_token(C, token));
}
struct token *dmrC_primary_expression(struct dmr_C *C, struct token *token, struct expression **tree)
{
struct expression *expr = NULL;
switch (dmrC_token_type(token)) {
case TOKEN_CHAR:
case TOKEN_CHAR_EMBEDDED_0:
case TOKEN_CHAR_EMBEDDED_1:
case TOKEN_CHAR_EMBEDDED_2:
case TOKEN_CHAR_EMBEDDED_3:
case TOKEN_WIDE_CHAR:
case TOKEN_WIDE_CHAR_EMBEDDED_0:
case TOKEN_WIDE_CHAR_EMBEDDED_1:
case TOKEN_WIDE_CHAR_EMBEDDED_2:
case TOKEN_WIDE_CHAR_EMBEDDED_3:
expr = dmrC_alloc_expression(C, token->pos, EXPR_VALUE);
expr->flags = Int_const_expr;
expr->ctype = dmrC_token_type(token) < TOKEN_WIDE_CHAR ? &C->S->int_ctype : &C->S->long_ctype;
dmrC_get_char_constant(C, token, &expr->value);
token = token->next;
break;
case TOKEN_NUMBER:
expr = dmrC_alloc_expression(C, token->pos, EXPR_VALUE);
get_number_value(C, expr, token); /* will see if it's an integer */
token = token->next;
break;
case TOKEN_ZERO_IDENT: {
expr = dmrC_alloc_expression(C, token->pos, EXPR_SYMBOL);
expr->flags = Int_const_expr;
expr->ctype = &C->S->int_ctype;
expr->symbol = &C->S->zero_int;
expr->symbol_name = token->ident;
token = token->next;
break;
}
case TOKEN_IDENT: {
struct symbol *sym = dmrC_lookup_symbol(token->ident, NS_SYMBOL | NS_TYPEDEF);
struct token *next = token->next;
if (!sym) {
sym = handle_func(C, token);
if (token->ident == C->S->__builtin_types_compatible_p_ident) {
token = builtin_types_compatible_p_expr(C, token, &expr);
break;
}
if (token->ident == C->S->__builtin_offsetof_ident) {
token = builtin_offsetof_expr(C, token, &expr);
break;
}
} else if (sym->enum_member) {
expr = dmrC_alloc_expression(C, token->pos, EXPR_VALUE);
*expr = *sym->initializer;
/* we want the right position reported, thus the copy */
expr->pos = token->pos;
expr->flags = Int_const_expr;
token = next;
break;
}
expr = dmrC_alloc_expression(C, token->pos, EXPR_SYMBOL);
/*
* We support types as real first-class citizens, with type
* comparisons etc:
*
* if (typeof(a) == int) ..
*/
if (sym && sym->ns == NS_TYPEDEF) {
dmrC_sparse_error(C, token->pos, "typename in expression");
sym = NULL;
}
expr->symbol_name = token->ident;
expr->symbol = sym;
token = next;
break;
}
case TOKEN_STRING:
case TOKEN_WIDE_STRING:
expr = dmrC_alloc_expression(C, token->pos, EXPR_STRING);
token = dmrC_get_string_constant(C, token, expr);
break;
case TOKEN_SPECIAL:
if (token->special == '(') {
expr = dmrC_alloc_expression(C, token->pos, EXPR_PREOP);
expr->op = '(';
token = dmrC_parens_expression(C, token, &expr->unop, "in expression");
if (expr->unop)
expr->flags = expr->unop->flags;
break;
}
if (token->special == '[' && dmrC_lookup_type(token->next)) {
expr = dmrC_alloc_expression(C, token->pos, EXPR_TYPE);
expr->flags = Int_const_expr; /* sic */
token = dmrC_typename(C, token->next, &expr->symbol, NULL);
token = dmrC_expect_token(C, token, ']', "in type expression");
break;
}
default:
;
}
*tree = expr;
return token;
}
static struct token *expression_list(struct dmr_C *C, struct token *token, struct expression_list **list)
{
while (!dmrC_match_op(token, ')')) {
struct expression *expr = NULL;
token = dmrC_assignment_expression(C, token, &expr);
if (!expr)
break;
dmrC_add_expression(C, list, expr);
if (!dmrC_match_op(token, ','))
break;
token = token->next;
}
return token;
}
/*
* extend to deal with the ambiguous C grammar for parsing
* a cast expressions followed by an initializer.
*/
static struct token *postfix_expression(struct dmr_C *C, struct token *token, struct expression **tree, struct expression *cast_init_expr)
{
struct expression *expr = cast_init_expr;
if (!expr)
token = dmrC_primary_expression(C, token, &expr);
while (expr && dmrC_token_type(token) == TOKEN_SPECIAL) {
switch (token->special) {
case '[': { /* Array dereference */
struct expression *deref = dmrC_alloc_expression(C, token->pos, EXPR_PREOP);
struct expression *add = dmrC_alloc_expression(C, token->pos, EXPR_BINOP);
deref->op = '*';
deref->unop = add;
add->op = '+';
add->left = expr;
token = dmrC_parse_expression(C, token->next, &add->right);
token = dmrC_expect_token(C, token, ']', "at end of array dereference");
expr = deref;
continue;
}
case SPECIAL_INCREMENT: /* Post-increment */
case SPECIAL_DECREMENT: { /* Post-decrement */
struct expression *post = dmrC_alloc_expression(C, token->pos, EXPR_POSTOP);
post->op = token->special;
post->unop = expr;
expr = post;
token = token->next;
continue;
}
case SPECIAL_DEREFERENCE: { /* Structure pointer member dereference */
/* "x->y" is just shorthand for "(*x).y" */
struct expression *inner = dmrC_alloc_expression(C, token->pos, EXPR_PREOP);
inner->op = '*';
inner->unop = expr;
expr = inner;
}
/* Fall through!! */
case '.': { /* Structure member dereference */
struct expression *deref = dmrC_alloc_expression(C, token->pos, EXPR_DEREF);
deref->op = '.';
deref->deref = expr;
token = token->next;
if (dmrC_token_type(token) != TOKEN_IDENT) {
dmrC_sparse_error(C, token->pos, "Expected member name");
break;
}
deref->member = token->ident;
token = token->next;
expr = deref;
continue;
}
case '(': { /* Function call */
struct expression *call = dmrC_alloc_expression(C, token->pos, EXPR_CALL);
call->op = '(';
call->fn = expr;
token = expression_list(C, token->next, &call->args);
token = dmrC_expect_token(C, token, ')', "in function call");
expr = call;
continue;
}
default:
break;
}
break;
}
*tree = expr;
return token;
}
static struct token *cast_expression(struct dmr_C *C, struct token *token, struct expression **tree);
static struct token *unary_expression(struct dmr_C *C, struct token *token, struct expression **tree);
static struct token *type_info_expression(struct dmr_C *C, struct token *token,
struct expression **tree, int type)
{
struct expression *expr = dmrC_alloc_expression(C, token->pos, type);
struct token *p;
*tree = expr;
expr->flags = Int_const_expr; /* XXX: VLA support will need that changed */
token = token->next;
if (!dmrC_match_op(token, '(') || !dmrC_lookup_type(token->next))
return unary_expression(C, token, &expr->cast_expression);
p = token;
token = dmrC_typename(C, token->next, &expr->cast_type, NULL);
if (!dmrC_match_op(token, ')')) {
static const char * error[] = {
[EXPR_SIZEOF] = "at end of sizeof",
[EXPR_ALIGNOF] = "at end of __alignof__",
[EXPR_PTRSIZEOF] = "at end of __sizeof_ptr__"
};
return dmrC_expect_token(C, token, ')', error[type]);
}
token = token->next;
/*
* C99 ambiguity: the typename might have been the beginning
* of a typed initializer expression..
*/
if (dmrC_match_op(token, '{')) {
struct expression *cast = dmrC_alloc_expression(C, p->pos, EXPR_CAST);
cast->cast_type = expr->cast_type;
expr->cast_type = NULL;
expr->cast_expression = cast;
token = dmrC_initializer(C, &cast->cast_expression, token);
token = postfix_expression(C, token, &expr->cast_expression, cast);
}
return token;
}
static struct token *unary_expression(struct dmr_C *C, struct token *token, struct expression **tree)
{
if (dmrC_token_type(token) == TOKEN_IDENT) {
struct ident *ident = token->ident;
if (ident->reserved) {
const struct {
struct ident *id;
int type;
} type_information[] = {
{ C->S->sizeof_ident, EXPR_SIZEOF },
{ C->S->__alignof___ident, EXPR_ALIGNOF },
{ C->S->__alignof_ident, EXPR_ALIGNOF },
{ C->S->_Alignof_ident, EXPR_ALIGNOF },
{ C->S->__sizeof_ptr___ident, EXPR_PTRSIZEOF },
};
int i;
for (i = 0; i < ARRAY_SIZE(type_information); i++) {
if (ident == type_information[i].id)
return type_info_expression(C, token, tree, type_information[i].type);
}
}
}
if (dmrC_token_type(token) == TOKEN_SPECIAL) {
if (match_oplist(token->special,
SPECIAL_INCREMENT, SPECIAL_DECREMENT,
'&', '*', 0)) {
struct expression *unop;
struct expression *unary;
struct token *next;
next = cast_expression(C, token->next, &unop);
if (!unop) {
dmrC_sparse_error(C, token->pos, "Syntax error in unary expression");
*tree = NULL;
return next;
}
unary = dmrC_alloc_expression(C, token->pos, EXPR_PREOP);
unary->op = token->special;
unary->unop = unop;
*tree = unary;
return next;
}
/* possibly constant ones */
if (match_oplist(token->special, '+', '-', '~', '!', 0)) {
struct expression *unop;
struct expression *unary;
struct token *next;
next = cast_expression(C, token->next, &unop);
if (!unop) {
dmrC_sparse_error(C, token->pos, "Syntax error in unary expression");
*tree = NULL;
return next;
}
unary = dmrC_alloc_expression(C, token->pos, EXPR_PREOP);
unary->op = token->special;
unary->unop = unop;
unary->flags = unop->flags & Int_const_expr;
*tree = unary;
return next;
}
/* Gcc extension: &&label gives the address of a label */
if (dmrC_match_op(token, SPECIAL_LOGICAL_AND) &&
dmrC_token_type(token->next) == TOKEN_IDENT) {
struct expression *label = dmrC_alloc_expression(C, token->pos, EXPR_LABEL);
struct symbol *sym = dmrC_label_symbol(C, token->next);
if (!(sym->ctype.modifiers & MOD_ADDRESSABLE)) {
sym->ctype.modifiers |= MOD_ADDRESSABLE;
dmrC_add_symbol(C, &C->P->function_computed_target_list, sym);
}
label->label_symbol = sym;
*tree = label;
return token->next->next;
}
}
return postfix_expression(C, token, tree, NULL);
}
/*
* Ambiguity: a '(' can be either a cast-expression or
* a primary-expression depending on whether it is followed
* by a type or not.
*
* additional ambiguity: a "cast expression" followed by
* an initializer is really a postfix-expression.
*/
static struct token *cast_expression(struct dmr_C *C, struct token *token, struct expression **tree)
{
if (dmrC_match_op(token, '(')) {
struct token *next = token->next;
if (dmrC_lookup_type(next)) {
struct expression *cast = dmrC_alloc_expression(C, next->pos, EXPR_CAST);
struct expression *v;
struct symbol *sym;
int is_force;
token = dmrC_typename(C, next, &sym, &is_force);
cast->cast_type = sym;
token = dmrC_expect_token(C, token, ')', "at end of cast operator");
if (dmrC_match_op(token, '{')) {
if (is_force)
dmrC_warning(C, sym->pos,
"[force] in compound literal");
token = dmrC_initializer(C, &cast->cast_expression, token);
return postfix_expression(C, token, tree, cast);
}
*tree = cast;
if (is_force)
cast->type = EXPR_FORCE_CAST;
token = cast_expression(C, token, &v);
if (!v)
return token;
cast->cast_expression = v;
if (v->flags & Int_const_expr)
cast->flags = Int_const_expr;
else if (v->flags & Float_literal) /* and _not_ int */
cast->flags = Int_const_expr | Float_literal;
return token;
}
}
return unary_expression(C, token, tree);
}
/*
* Generic left-to-right binop parsing
*
* This _really_ needs to be inlined, because that makes the inner
* function call statically deterministic rather than a totally
* unpredictable indirect call. But gcc-3 is so "clever" that it
* doesn't do so by default even when you tell it to inline it.
*
* Making it a macro avoids the inlining problem, and also means
* that we can pass in the op-comparison as an expression rather
* than create a data structure for it.
*/
#define LR_BINOP_EXPRESSION(C, __token, tree, type, inner, compare) \
struct expression *left = NULL; \
struct token * next = inner(C, __token, &left); \
\
if (left) { \
while (dmrC_token_type(next) == TOKEN_SPECIAL) { \
struct expression *top, *right = NULL; \
int op = next->special; \
\
if (!(compare)) \
goto out; \
top = dmrC_alloc_expression(C, next->pos, type); \
next = inner(C, next->next, &right); \
if (!right) { \
dmrC_sparse_error(C, next->pos, "No right hand side of '%s'-expression", dmrC_show_special(C, op)); \
break; \
} \
top->flags = left->flags & right->flags \
& Int_const_expr; \
top->op = op; \
top->left = left; \
top->right = right; \
left = top; \
} \
} \
out: \
*tree = left; \
return next; \
static struct token *multiplicative_expression(struct dmr_C *C, struct token *token, struct expression **tree)
{
LR_BINOP_EXPRESSION(C,
token, tree, EXPR_BINOP, cast_expression,
(op == '*') || (op == '/') || (op == '%')
);
}
static struct token *additive_expression(struct dmr_C *C, struct token *token, struct expression **tree)
{
LR_BINOP_EXPRESSION(C,
token, tree, EXPR_BINOP, multiplicative_expression,
(op == '+') || (op == '-')
);
}
static struct token *shift_expression(struct dmr_C *C, struct token *token, struct expression **tree)
{
LR_BINOP_EXPRESSION(C,
token, tree, EXPR_BINOP, additive_expression,
(op == SPECIAL_LEFTSHIFT) || (op == SPECIAL_RIGHTSHIFT)
);
}
static struct token *relational_expression(struct dmr_C *C, struct token *token, struct expression **tree)
{
LR_BINOP_EXPRESSION(C,
token, tree, EXPR_COMPARE, shift_expression,
(op == '<') || (op == '>') ||
(op == SPECIAL_LTE) || (op == SPECIAL_GTE)
);
}
static struct token *equality_expression(struct dmr_C *C, struct token *token, struct expression **tree)
{
LR_BINOP_EXPRESSION(C,
token, tree, EXPR_COMPARE, relational_expression,
(op == SPECIAL_EQUAL) || (op == SPECIAL_NOTEQUAL)
);
}
static struct token *bitwise_and_expression(struct dmr_C *C, struct token *token, struct expression **tree)
{
LR_BINOP_EXPRESSION(C,
token, tree, EXPR_BINOP, equality_expression,
(op == '&')
);
}
static struct token *bitwise_xor_expression(struct dmr_C *C, struct token *token, struct expression **tree)
{
LR_BINOP_EXPRESSION(C,
token, tree, EXPR_BINOP, bitwise_and_expression,
(op == '^')
);
}
static struct token *bitwise_or_expression(struct dmr_C *C, struct token *token, struct expression **tree)
{
LR_BINOP_EXPRESSION(C,
token, tree, EXPR_BINOP, bitwise_xor_expression,
(op == '|')
);
}
static struct token *logical_and_expression(struct dmr_C *C, struct token *token, struct expression **tree)
{
LR_BINOP_EXPRESSION(C,
token, tree, EXPR_LOGICAL, bitwise_or_expression,
(op == SPECIAL_LOGICAL_AND)
);
}
static struct token *logical_or_expression(struct dmr_C *C, struct token *token, struct expression **tree)
{
LR_BINOP_EXPRESSION(C,
token, tree, EXPR_LOGICAL, logical_and_expression,
(op == SPECIAL_LOGICAL_OR)
);
}
struct token *dmrC_conditional_expression(struct dmr_C *C, struct token *token, struct expression **tree)
{
token = logical_or_expression(C, token, tree);
if (*tree && dmrC_match_op(token, '?')) {
struct expression *expr = dmrC_alloc_expression(C, token->pos, EXPR_CONDITIONAL);
expr->op = token->special;
expr->left = *tree;
*tree = expr;
token = dmrC_parse_expression(C, token->next, &expr->cond_true);
token = dmrC_expect_token(C, token, ':', "in conditional expression");
token = dmrC_conditional_expression(C, token, &expr->cond_false);
if (expr->left && expr->cond_false) {
int is_const = expr->left->flags &
expr->cond_false->flags &
Int_const_expr;
if (expr->cond_true)
is_const &= expr->cond_true->flags;
expr->flags = is_const;
}
}
return token;
}
struct token *dmrC_assignment_expression(struct dmr_C *C, struct token *token, struct expression **tree)
{
token = dmrC_conditional_expression(C, token, tree);
if (*tree && dmrC_token_type(token) == TOKEN_SPECIAL) {
static const int assignments[] = {
'=',
SPECIAL_ADD_ASSIGN, SPECIAL_SUB_ASSIGN,
SPECIAL_MUL_ASSIGN, SPECIAL_DIV_ASSIGN,
SPECIAL_MOD_ASSIGN, SPECIAL_SHL_ASSIGN,
SPECIAL_SHR_ASSIGN, SPECIAL_AND_ASSIGN,
SPECIAL_OR_ASSIGN, SPECIAL_XOR_ASSIGN };
int i, op = token->special;
for (i = 0; i < ARRAY_SIZE(assignments); i++)
if (assignments[i] == op) {
struct expression * expr = dmrC_alloc_expression(C, token->pos, EXPR_ASSIGNMENT);
expr->left = *tree;
expr->op = op;
*tree = expr;
return dmrC_assignment_expression(C, token->next, &expr->right);
}
}
return token;
}
static struct token *comma_expression(struct dmr_C *C, struct token *token, struct expression **tree)
{
LR_BINOP_EXPRESSION(C,
token, tree, EXPR_COMMA, dmrC_assignment_expression,
(op == ',')
);
}
struct token *dmrC_parse_expression(struct dmr_C *C, struct token *token, struct expression **tree)
{
return comma_expression(C, token,tree);
}

@ -0,0 +1,265 @@
#ifndef DMR_C_EXPRESSION_H
#define DMR_C_EXPRESSION_H
/*
* sparse/expression.h
*
* Copyright (C) 2003 Transmeta Corp.
* 2003 Linus Torvalds
*
* 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.
*
* Declarations and helper functions for expression parsing.
*/
/*
* This version is part of the dmr_c project.
* Copyright (C) 2017 Dibyendu Majumdar
*/
#include <allocate.h>
#include <lib.h>
#include <symbol.h>
#ifdef __cplusplus
extern "C" {
#endif
enum expression_type {
EXPR_VALUE = 1,
EXPR_STRING,
EXPR_SYMBOL,
EXPR_TYPE,
EXPR_BINOP,
EXPR_ASSIGNMENT,
EXPR_LOGICAL,
EXPR_DEREF,
EXPR_PREOP,
EXPR_POSTOP,
EXPR_CAST,
EXPR_FORCE_CAST,
EXPR_IMPLIED_CAST,
EXPR_SIZEOF,
EXPR_ALIGNOF,
EXPR_PTRSIZEOF,
EXPR_CONDITIONAL,
EXPR_SELECT, // a "safe" conditional expression
EXPR_STATEMENT,
EXPR_CALL,
EXPR_COMMA,
EXPR_COMPARE,
EXPR_LABEL,
EXPR_INITIALIZER, // initializer list
EXPR_IDENTIFIER, // identifier in initializer
EXPR_INDEX, // index in initializer
EXPR_POS, // position in initializer
EXPR_FVALUE,
EXPR_SLICE,
EXPR_OFFSETOF,
};
enum {
Int_const_expr = 1,
Float_literal = 2,
}; /* for expr->flags */
enum {
Taint_comma = 1,
}; /* for expr->taint */
DECLARE_PTR_LIST(expression_list, struct expression);
struct expression {
enum expression_type type:8;
unsigned flags:8;
int op;
struct position pos;
struct symbol *ctype;
union {
// EXPR_VALUE
struct {
unsigned long long value;
unsigned taint;
};
// EXPR_FVALUE
long double fvalue;
// EXPR_STRING
struct {
int wide;
struct string *string;
};
// EXPR_UNOP, EXPR_PREOP and EXPR_POSTOP
struct /* unop */ {
struct expression *unop;
unsigned long op_value;
};
// EXPR_SYMBOL, EXPR_TYPE
struct /* symbol_arg */ {
struct symbol *symbol;
struct ident *symbol_name;
};
// EXPR_STATEMENT
struct statement *statement;
// EXPR_BINOP, EXPR_COMMA, EXPR_COMPARE, EXPR_LOGICAL and EXPR_ASSIGNMENT
struct /* binop_arg */ {
struct expression *left, *right;
};
// EXPR_DEREF
struct /* deref_arg */ {
struct expression *deref;
struct ident *member;
};
// EXPR_SLICE
struct /* slice */ {
struct expression *base;
unsigned r_bitpos, r_nrbits;
};
// EXPR_CAST and EXPR_SIZEOF
struct /* cast_arg */ {
struct symbol *cast_type;
struct expression *cast_expression;
};
// EXPR_CONDITIONAL
// EXPR_SELECT
struct /* conditional_expr */ {
struct expression *conditional, *cond_true, *cond_false;
};
// EXPR_CALL
struct /* call_expr */ {
struct expression *fn;
struct expression_list *args;
};
// EXPR_LABEL
struct /* label_expr */ {
struct symbol *label_symbol;
};
// EXPR_INITIALIZER
struct expression_list *expr_list;
// EXPR_IDENTIFIER
struct /* ident_expr */ {
int offset;
struct ident *expr_ident;
struct symbol *field;
struct expression *ident_expression;
};
// EXPR_INDEX
struct /* index_expr */ {
unsigned int idx_from, idx_to;
struct expression *idx_expression;
};
// EXPR_POS
struct /* initpos_expr */ {
unsigned int init_offset, init_nr;
struct expression *init_expr;
};
// EXPR_OFFSETOF
struct {
struct symbol *in;
struct expression *down;
union {
struct ident *ident;
struct expression *index;
};
};
};
};
long long dmrC_get_expression_value_silent(struct dmr_C *C, struct expression *expr);
extern struct symbol *dmrC_evaluate_expression(struct dmr_C *C, struct expression *);
long long dmrC_get_expression_value(struct dmr_C *C, struct expression *);
/* Constant expression values */
int dmrC_is_zero_constant(struct dmr_C *C, struct expression *);
int dmrC_expr_truth_value(struct dmr_C *C, struct expression *expr);
long long dmrC_const_expression_value(struct dmr_C *C, struct expression *);
/* Expression parsing */
struct token *dmrC_conditional_expression(struct dmr_C *C, struct token *token,
struct expression **tree);
struct token *dmrC_primary_expression(struct dmr_C *C, struct token *token, struct expression **tree);
struct token *dmrC_parens_expression(struct dmr_C *C, struct token *token, struct expression **expr,
const char *where);
struct token *dmrC_assignment_expression(struct dmr_C *C, struct token *token,
struct expression **tree);
extern void dmrC_evaluate_symbol_list(struct dmr_C *C, struct symbol_list *list);
extern struct symbol *dmrC_evaluate_statement(struct dmr_C *C, struct statement *stmt);
extern int dmrC_expand_symbol(struct dmr_C *C, struct symbol *);
static inline struct expression *dmrC_alloc_expression(struct dmr_C *C, struct position pos, int type)
{
struct expression *expr = (struct expression *)dmrC_allocator_allocate(&C->expression_allocator, 0);
expr->type = (enum expression_type)type;
expr->pos = pos;
return expr;
}
static inline struct expression *dmrC_alloc_const_expression(struct dmr_C *C, struct position pos,
int value)
{
struct expression *expr = (struct expression *)dmrC_allocator_allocate(&C->expression_allocator, 0);
expr->type = EXPR_VALUE;
expr->pos = pos;
expr->value = value;
expr->ctype = &C->S->int_ctype;
return expr;
}
/* Type name parsing */
struct token *dmrC_typename(struct dmr_C *C, struct token *, struct symbol **, int *);
static inline int dmrC_lookup_type(struct token *token)
{
if (token->pos.type == TOKEN_IDENT) {
struct symbol *sym = dmrC_lookup_symbol(
token->ident,
(enum namespace_type)(NS_SYMBOL | NS_TYPEDEF));
return sym && (sym->ns & NS_TYPEDEF);
}
return 0;
}
/* Statement parsing */
struct statement *dmrC_alloc_statement(struct dmr_C *C, struct position pos, int type);
struct token *dmrC_initializer(struct dmr_C *C, struct expression **tree, struct token *token);
struct token *dmrC_compound_statement(struct dmr_C *C, struct token *, struct statement *);
/* The preprocessor calls this 'dmrC_constant_expression()' */
#define dmrC_constant_expression(C, token, tree) dmrC_conditional_expression(C, token, tree)
/* Cast folding of constant values.. */
void dmrC_cast_value(struct dmr_C *C, struct expression *expr, struct symbol *newtype,
struct expression *old, struct symbol *oldtype);
static inline struct expression *dmrC_first_expression(struct expression_list *head)
{
return (struct expression *) ptrlist_first((struct ptr_list *)head);
}
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

@ -0,0 +1,67 @@
#ifndef DMR_C_FLOW_H
#define DMR_C_FLOW_H
/*
* Flow - walk the linearized flowgraph, simplifying it as we
* go along.
*
* Copyright (C) 2004 Linus Torvalds
*/
#include <lib.h>
#ifdef __cplusplus
extern "C" {
#endif
#define REPEAT_CSE 1
#define REPEAT_SYMBOL_CLEANUP 2
#define REPEAT_CFG_CLEANUP 3
struct entrypoint;
struct instruction;
extern int dmrC_simplify_flow(struct dmr_C *C, struct entrypoint *ep);
extern void dmrC_simplify_symbol_usage(struct dmr_C *C, struct entrypoint *ep);
extern void dmrC_simplify_memops(struct dmr_C *C, struct entrypoint *ep);
extern void dmrC_pack_basic_blocks(struct dmr_C *C, struct entrypoint *ep);
extern void dmrC_convert_instruction_target(struct dmr_C *C, struct instruction *insn, pseudo_t src);
extern void dmrC_cleanup_and_cse(struct dmr_C *C, struct entrypoint *ep);
extern int dmrC_simplify_instruction(struct dmr_C *C, struct instruction *);
extern void dmrC_kill_bb(struct dmr_C *C, struct basic_block *);
extern void dmrC_kill_use(struct dmr_C *C, pseudo_t *usep);
extern void dmrC_remove_use(struct dmr_C *C, pseudo_t *);
extern void dmrC_kill_insn(struct dmr_C *C, struct instruction *, int force);
static inline void dmrC_kill_instruction(struct dmr_C *C, struct instruction *insn)
{
dmrC_kill_insn(C, insn, 0);
}
static inline void dmrC_kill_instruction_force(struct dmr_C *C, struct instruction *insn)
{
dmrC_kill_insn(C, insn, 1);
}
extern void dmrC_kill_unreachable_bbs(struct dmr_C *C, struct entrypoint *ep);
void dmrC_check_access(struct dmr_C *C, struct instruction *insn);
void dmrC_convert_load_instruction(struct dmr_C *C, struct instruction *, pseudo_t);
void dmrC_rewrite_load_instruction(struct dmr_C *C, struct instruction *, struct pseudo_list *);
int dmrC_dominates(struct dmr_C *C, pseudo_t pseudo, struct instruction *insn, struct instruction *dom, int local);
extern void dmrC_clear_liveness(struct entrypoint *ep);
extern void dmrC_track_pseudo_liveness(struct dmr_C *C, struct entrypoint *ep);
extern void dmrC_track_pseudo_death(struct dmr_C *C, struct entrypoint *ep);
extern void dmrC_track_phi_uses(struct dmr_C *C, struct instruction *insn);
extern void dmrC_vrfy_flow(struct entrypoint *ep);
extern int dmrC_pseudo_in_list(struct pseudo_list *list, pseudo_t pseudo);
#ifdef __cplusplus
}
#endif
#endif

@ -0,0 +1,207 @@
GCC_ATTR(BELOW100)
GCC_ATTR(OS_Task)
GCC_ATTR(OS_main)
GCC_ATTR(OS_task)
GCC_ATTR(abi_tag)
GCC_ATTR(absdata)
GCC_ATTR(address)
GCC_ATTR(alias)
GCC_ATTR(aligned)
GCC_ATTR(alloc_align)
GCC_ATTR(alloc_size)
GCC_ATTR(altivec)
GCC_ATTR(always_inline)
GCC_ATTR(artificial)
GCC_ATTR(assume_aligned)
GCC_ATTR(bank_switch)
GCC_ATTR(based)
GCC_ATTR(below100)
GCC_ATTR(bnd_instrument)
GCC_ATTR(bnd_legacy)
GCC_ATTR(bnd_variable_size)
GCC_ATTR(break_handler)
GCC_ATTR(brk_interrupt)
GCC_ATTR(callee_pop_aggregate_return)
GCC_ATTR(cb)
GCC_ATTR(cdecl)
GCC_ATTR(cleanup)
GCC_ATTR(cmse_nonsecure_call)
GCC_ATTR(cmse_nonsecure_entry)
GCC_ATTR(cold)
GCC_ATTR(common)
GCC_ATTR(common_object)
GCC_ATTR(const)
GCC_ATTR(constructor)
GCC_ATTR(critical)
GCC_ATTR(default)
GCC_ATTR(deprecated)
GCC_ATTR(designated_init)
GCC_ATTR(destructor)
GCC_ATTR(disinterrupt)
GCC_ATTR(dllexport)
GCC_ATTR(dllimport)
GCC_ATTR(eightbit_data)
GCC_ATTR(either)
GCC_ATTR(error)
GCC_ATTR(exception)
GCC_ATTR(exception_handler)
GCC_ATTR(externally_visible)
GCC_ATTR(fallthrough)
GCC_ATTR(far)
GCC_ATTR(fast_interrupt)
GCC_ATTR(fastcall)
GCC_ATTR(flatten)
GCC_ATTR(force_align_arg_pointer)
GCC_ATTR(format)
GCC_ATTR(format_arg)
GCC_ATTR(forwarder_section)
GCC_ATTR(function_vector)
GCC_ATTR(gcc_struct)
GCC_ATTR(gnu_inline)
GCC_ATTR(hidden)
GCC_ATTR(hot)
GCC_ATTR(hotpatch)
GCC_ATTR(ifunc)
GCC_ATTR(init_priority)
GCC_ATTR(interfacearm)
GCC_ATTR(internal)
GCC_ATTR(interrupt)
GCC_ATTR(interrupt_handler)
GCC_ATTR(interrupt_thread)
GCC_ATTR(io)
GCC_ATTR(io_low)
GCC_ATTR(isr)
GCC_ATTR(keep_interrupts_masked)
GCC_ATTR(kernel)
GCC_ATTR(kspisusp)
GCC_ATTR(l1_data)
GCC_ATTR(l1_data_A)
GCC_ATTR(l1_data_B)
GCC_ATTR(l1_text)
GCC_ATTR(l2)
GCC_ATTR(leaf)
GCC_ATTR(long_call)
GCC_ATTR(longcall)
GCC_ATTR(lower)
GCC_ATTR(malloc)
GCC_ATTR(may_alias)
GCC_ATTR(maybe_unused)
GCC_ATTR(medium_call)
GCC_ATTR(micromips)
GCC_ATTR(mips16)
GCC_ATTR(mode)
GCC_ATTR(model)
GCC_ATTR(monitor)
GCC_ATTR(ms_abi)
GCC_ATTR(ms_hook_prologue)
GCC_ATTR(ms_struct)
GCC_ATTR(naked)
GCC_ATTR(near)
GCC_ATTR(nested)
GCC_ATTR(nested_ready)
GCC_ATTR(nesting)
GCC_ATTR(nmi)
GCC_ATTR(nmi_handler)
GCC_ATTR(no_address_safety_analysis)
GCC_ATTR(no_caller_saved_registers)
GCC_ATTR(no_gccisr)
GCC_ATTR(no_icf)
GCC_ATTR(no_instrument_function)
GCC_ATTR(no_profile_instrument_function)
GCC_ATTR(no_reorder)
GCC_ATTR(no_sanitize)
GCC_ATTR(no_sanitize_address)
GCC_ATTR(no_sanitize_thread)
GCC_ATTR(no_sanitize_undefined)
GCC_ATTR(no_split_stack)
GCC_ATTR(no_stack_limit)
GCC_ATTR(noclone)
GCC_ATTR(nocommon)
GCC_ATTR(nocompression)
GCC_ATTR(nodiscard)
GCC_ATTR(noinit)
GCC_ATTR(noinline)
GCC_ATTR(noipa)
GCC_ATTR(nomicromips)
GCC_ATTR(nomips16)
GCC_ATTR(nonnull)
GCC_ATTR(noplt)
GCC_ATTR(noreturn)
GCC_ATTR(nosave_low_regs)
GCC_ATTR(not_nested)
GCC_ATTR(nothrow)
GCC_ATTR(notshared)
GCC_ATTR(optimize)
GCC_ATTR(packed)
GCC_ATTR(partial_save)
GCC_ATTR(patchable_function_entry)
GCC_ATTR(pcs)
GCC_ATTR(persistent)
GCC_ATTR(progmem)
GCC_ATTR(protected)
GCC_ATTR(pure)
GCC_ATTR(reentrant)
GCC_ATTR(regparm)
GCC_ATTR(renesas)
GCC_ATTR(resbank)
GCC_ATTR(reset)
GCC_ATTR(returns_nonnull)
GCC_ATTR(returns_twice)
GCC_ATTR(s390_vector_bool)
GCC_ATTR(saddr)
GCC_ATTR(save_all)
GCC_ATTR(save_volatiles)
GCC_ATTR(saveall)
GCC_ATTR(scalar_storage_order)
GCC_ATTR(sda)
GCC_ATTR(section)
GCC_ATTR(selectany)
GCC_ATTR(sentinel)
GCC_ATTR(shared)
GCC_ATTR(short_call)
GCC_ATTR(shortcall)
GCC_ATTR(signal)
GCC_ATTR(simd)
GCC_ATTR(sp_switch)
GCC_ATTR(spu_vector)
GCC_ATTR(sseregparm)
GCC_ATTR(stack_protect)
GCC_ATTR(stdcall)
GCC_ATTR(syscall_linkage)
GCC_ATTR(sysv_abi)
GCC_ATTR(target)
GCC_ATTR(target_clones)
GCC_ATTR(tda)
GCC_ATTR(thiscall)
GCC_ATTR(tiny)
GCC_ATTR(tiny_data)
GCC_ATTR(tls_model)
GCC_ATTR(transaction_callable)
GCC_ATTR(transaction_may_cancel_outer)
GCC_ATTR(transaction_pure)
GCC_ATTR(transaction_safe)
GCC_ATTR(transaction_safe_dynamic)
GCC_ATTR(transaction_unsafe)
GCC_ATTR(transaction_wrap)
GCC_ATTR(transparent_union)
GCC_ATTR(trap_exit)
GCC_ATTR(trapa_handler)
GCC_ATTR(unused)
GCC_ATTR(upper)
GCC_ATTR(use_debug_exception_return)
GCC_ATTR(use_shadow_register_set)
GCC_ATTR(used)
GCC_ATTR(vector)
GCC_ATTR(vector_size)
GCC_ATTR(version_id)
GCC_ATTR(visibility)
GCC_ATTR(vliw)
GCC_ATTR(volatile)
GCC_ATTR(wakeup)
GCC_ATTR(warm)
GCC_ATTR(warn_unused)
GCC_ATTR(warn_unused_result)
GCC_ATTR(warning)
GCC_ATTR(weak)
GCC_ATTR(weakref)
GCC_ATTR(zda)

@ -0,0 +1,140 @@
#define IDENT(n) __IDENT(n## _ident, #n, 0)
#define IDENT_RESERVED(n) __IDENT(n## _ident, #n, 1)
/* Basic C reserved words.. */
IDENT_RESERVED(sizeof);
IDENT_RESERVED(if);
IDENT_RESERVED(else);
IDENT_RESERVED(return);
IDENT_RESERVED(switch);
IDENT_RESERVED(case);
IDENT_RESERVED(default);
IDENT_RESERVED(break);
IDENT_RESERVED(continue);
IDENT_RESERVED(for);
IDENT_RESERVED(while);
IDENT_RESERVED(do);
IDENT_RESERVED(goto);
/* C typenames. They get marked as reserved when initialized */
IDENT(struct);
IDENT(union);
IDENT(enum);
IDENT(__attribute); IDENT(__attribute__);
IDENT(volatile); IDENT(__volatile); IDENT(__volatile__);
IDENT(double);
/* C storage classes. They get marked as reserved when initialized */
IDENT(static);
/* C99 keywords */
IDENT(restrict); IDENT(__restrict); IDENT(__restrict__);
IDENT(_Bool);
IDENT_RESERVED(_Complex);
IDENT_RESERVED(_Imaginary);
/* C11 keywords */
IDENT(_Alignas);
IDENT_RESERVED(_Alignof);
IDENT_RESERVED(_Atomic);
IDENT_RESERVED(_Generic);
IDENT(_Noreturn);
IDENT_RESERVED(_Static_assert);
IDENT(_Thread_local);
/* Special case for L'\t' */
IDENT(L);
/* Extended gcc identifiers */
IDENT(asm); IDENT_RESERVED(__asm); IDENT_RESERVED(__asm__);
IDENT(alignof); IDENT_RESERVED(__alignof); IDENT_RESERVED(__alignof__);
IDENT_RESERVED(__sizeof_ptr__);
IDENT_RESERVED(__builtin_types_compatible_p);
IDENT_RESERVED(__builtin_offsetof);
IDENT_RESERVED(__label__);
/* Attribute names */
IDENT(packed); IDENT(__packed__);
IDENT(aligned); IDENT(__aligned__);
IDENT(nocast);
IDENT(noderef);
IDENT(safe);
IDENT(force);
IDENT(address_space);
IDENT(context);
IDENT(mode); IDENT(__mode__);
IDENT(QI); IDENT(__QI__);
IDENT(HI); IDENT(__HI__);
IDENT(SI); IDENT(__SI__);
IDENT(DI); IDENT(__DI__);
IDENT(word); IDENT(__word__);
IDENT(format); IDENT(__format__);
IDENT(section); IDENT(__section__);
IDENT(unused); IDENT(__unused__);
IDENT(const); IDENT(__const); IDENT(__const__);
IDENT(used); IDENT(__used__);
IDENT(warn_unused_result); IDENT(__warn_unused_result__);
IDENT(noinline); IDENT(__noinline__);
IDENT(deprecated); IDENT(__deprecated__);
IDENT(noreturn); IDENT(__noreturn__);
IDENT(regparm); IDENT(__regparm__);
IDENT(weak); IDENT(__weak__);
IDENT(no_instrument_function); IDENT(__no_instrument_function__);
IDENT(sentinel); IDENT(__sentinel__);
IDENT(alias); IDENT(__alias__);
IDENT(pure); IDENT(__pure__);
IDENT(always_inline); IDENT(__always_inline__);
IDENT(syscall_linkage); IDENT(__syscall_linkage__);
IDENT(visibility); IDENT(__visibility__);
IDENT(bitwise); IDENT(__bitwise__);
IDENT(model); IDENT(__model__);
IDENT(format_arg); IDENT(__format_arg__);
IDENT(nothrow); IDENT(__nothrow); IDENT(__nothrow__);
IDENT(__transparent_union__);
IDENT(malloc);
IDENT(__malloc__);
IDENT(nonnull); IDENT(__nonnull); IDENT(__nonnull__);
IDENT(constructor); IDENT(__constructor__);
IDENT(destructor); IDENT(__destructor__);
IDENT(cold); IDENT(__cold__);
IDENT(hot); IDENT(__hot__);
IDENT(cdecl); IDENT(__cdecl__);
IDENT(stdcall); IDENT(__stdcall__);
IDENT(fastcall); IDENT(__fastcall__);
IDENT(dllimport); IDENT(__dllimport__);
IDENT(dllexport); IDENT(__dllexport__);
IDENT(artificial); IDENT(__artificial__);
IDENT(leaf); IDENT(__leaf__);
IDENT(vector_size); IDENT(__vector_size__);
IDENT(error); IDENT(__error__);
/* Preprocessor idents. Direct use of __IDENT avoids mentioning the keyword
* itself by name, preventing these tokens from expanding when compiling
* sparse. */
IDENT(defined);
IDENT(once);
__IDENT(pragma_ident, "__pragma__", 0);
__IDENT(__VA_ARGS___ident, "__VA_ARGS__", 0);
__IDENT(__LINE___ident, "__LINE__", 0);
__IDENT(__FILE___ident, "__FILE__", 0);
__IDENT(__DATE___ident, "__DATE__", 0);
__IDENT(__TIME___ident, "__TIME__", 0);
__IDENT(__func___ident, "__func__", 0);
__IDENT(__FUNCTION___ident, "__FUNCTION__", 0);
__IDENT(__PRETTY_FUNCTION___ident, "__PRETTY_FUNCTION__", 0);
__IDENT(__COUNTER___ident, "__COUNTER__", 0);
/* Sparse commands */
IDENT_RESERVED(__context__);
IDENT_RESERVED(__range__);
/* Magic function names we recognize */
IDENT(memset); IDENT(memcpy);
IDENT(copy_to_user); IDENT(copy_from_user);
IDENT(main);
#undef __IDENT
#undef IDENT
#undef IDENT_RESERVED

@ -0,0 +1,590 @@
/*
* Sparse - a semantic source parser.
*
* Copyright (C) 2003 Transmeta Corp.
* 2003-2004 Linus Torvalds
*
* 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.
*/
/*
* This version is part of the dmr_c project.
* Copyright (C) 2017 Dibyendu Majumdar
*/
#include <stdlib.h>
#include <stdio.h>
#include <port.h>
#include <lib.h>
#include <allocate.h>
#include <token.h>
#include <parse.h>
#include <symbol.h>
#include <expression.h>
static struct expression * dup_expression(struct dmr_C *C, struct expression *expr)
{
struct expression *dup = dmrC_alloc_expression(C, expr->pos, expr->type);
*dup = *expr;
return dup;
}
static struct statement * dup_statement(struct dmr_C *C, struct statement *stmt)
{
struct statement *dup = dmrC_alloc_statement(C, stmt->pos, stmt->type);
*dup = *stmt;
return dup;
}
static struct symbol *copy_symbol(struct dmr_C *C, struct position pos, struct symbol *sym)
{
if (!sym)
return sym;
if (sym->ctype.modifiers & (MOD_STATIC | MOD_EXTERN | MOD_TOPLEVEL | MOD_INLINE))
return sym;
if (!sym->replace) {
dmrC_warning(C, pos, "unreplaced symbol '%s'", dmrC_show_ident(C, sym->ident));
return sym;
}
return sym->replace;
}
static struct symbol_list *copy_symbol_list(struct dmr_C *C, struct symbol_list *src)
{
struct symbol_list *dst = NULL;
struct symbol *sym;
FOR_EACH_PTR(src, sym) {
struct symbol *newsym = copy_symbol(C, sym->pos, sym);
dmrC_add_symbol(C, &dst, newsym);
} END_FOR_EACH_PTR(sym);
return dst;
}
static struct expression * copy_expression(struct dmr_C *C, struct expression *expr)
{
if (!expr)
return NULL;
switch (expr->type) {
/*
* EXPR_SYMBOL is the interesting case, we may need to replace the
* symbol to the new copy.
*/
case EXPR_SYMBOL: {
struct symbol *sym = copy_symbol(C, expr->pos, expr->symbol);
if (sym == expr->symbol)
break;
expr = dup_expression(C, expr);
expr->symbol = sym;
break;
}
/* Atomics, never change, just return the expression directly */
case EXPR_VALUE:
case EXPR_STRING:
case EXPR_FVALUE:
case EXPR_TYPE:
break;
/* Unops: check if the subexpression is unique */
case EXPR_PREOP:
case EXPR_POSTOP: {
struct expression *unop = copy_expression(C, expr->unop);
if (expr->unop == unop)
break;
expr = dup_expression(C, expr);
expr->unop = unop;
break;
}
case EXPR_SLICE: {
struct expression *base = copy_expression(C, expr->base);
expr = dup_expression(C, expr);
expr->base = base;
break;
}
/* Binops: copy left/right expressions */
case EXPR_BINOP:
case EXPR_COMMA:
case EXPR_COMPARE:
case EXPR_LOGICAL: {
struct expression *left = copy_expression(C, expr->left);
struct expression *right = copy_expression(C, expr->right);
if (left == expr->left && right == expr->right)
break;
expr = dup_expression(C, expr);
expr->left = left;
expr->right = right;
break;
}
case EXPR_ASSIGNMENT: {
struct expression *left = copy_expression(C, expr->left);
struct expression *right = copy_expression(C, expr->right);
if (expr->op == '=' && left == expr->left && right == expr->right)
break;
expr = dup_expression(C, expr);
expr->left = left;
expr->right = right;
break;
}
/* Dereference */
case EXPR_DEREF: {
struct expression *deref = copy_expression(C, expr->deref);
expr = dup_expression(C, expr);
expr->deref = deref;
break;
}
/* Cast/sizeof/__alignof__ */
case EXPR_CAST:
if (expr->cast_expression->type == EXPR_INITIALIZER) {
struct expression *cast = expr->cast_expression;
struct symbol *sym = expr->cast_type;
expr = dup_expression(C, expr);
expr->cast_expression = copy_expression(C, cast);
expr->cast_type = dmrC_alloc_symbol(C->S, sym->pos, sym->type);
*expr->cast_type = *sym;
break;
}
case EXPR_FORCE_CAST:
case EXPR_IMPLIED_CAST:
case EXPR_SIZEOF:
case EXPR_PTRSIZEOF:
case EXPR_ALIGNOF: {
struct expression *cast = copy_expression(C, expr->cast_expression);
if (cast == expr->cast_expression)
break;
expr = dup_expression(C, expr);
expr->cast_expression = cast;
break;
}
/* Conditional expression */
case EXPR_SELECT:
case EXPR_CONDITIONAL: {
struct expression *cond = copy_expression(C, expr->conditional);
struct expression *truee = copy_expression(C, expr->cond_true);
struct expression *falsee = copy_expression(C, expr->cond_false);
if (cond == expr->conditional && truee == expr->cond_true && falsee == expr->cond_false)
break;
expr = dup_expression(C, expr);
expr->conditional = cond;
expr->cond_true = truee;
expr->cond_false = falsee;
break;
}
/* Statement expression */
case EXPR_STATEMENT: {
struct statement *stmt = dmrC_alloc_statement(C, expr->pos, STMT_COMPOUND);
dmrC_copy_statement(C, expr->statement, stmt);
expr = dup_expression(C, expr);
expr->statement = stmt;
break;
}
/* Call expression */
case EXPR_CALL: {
struct expression *fn = copy_expression(C, expr->fn);
struct expression_list *list = expr->args;
struct expression *arg;
expr = dup_expression(C, expr);
expr->fn = fn;
expr->args = NULL;
FOR_EACH_PTR(list, arg) {
dmrC_add_expression(C, &expr->args, copy_expression(C, arg));
} END_FOR_EACH_PTR(arg);
break;
}
/* Initializer list statement */
case EXPR_INITIALIZER: {
struct expression_list *list = expr->expr_list;
struct expression *entry;
expr = dup_expression(C, expr);
expr->expr_list = NULL;
FOR_EACH_PTR(list, entry) {
dmrC_add_expression(C, &expr->expr_list, copy_expression(C, entry));
} END_FOR_EACH_PTR(entry);
break;
}
/* Label in inline function - hmm. */
case EXPR_LABEL: {
struct symbol *label_symbol = copy_symbol(C, expr->pos, expr->label_symbol);
expr = dup_expression(C, expr);
expr->label_symbol = label_symbol;
break;
}
case EXPR_INDEX: {
struct expression *sub_expr = copy_expression(C, expr->idx_expression);
expr = dup_expression(C, expr);
expr->idx_expression = sub_expr;
break;
}
case EXPR_IDENTIFIER: {
struct expression *sub_expr = copy_expression(C, expr->ident_expression);
expr = dup_expression(C, expr);
expr->ident_expression = sub_expr;
break;
}
/* Position in initializer.. */
case EXPR_POS: {
struct expression *val = copy_expression(C, expr->init_expr);
expr = dup_expression(C, expr);
expr->init_expr = val;
break;
}
case EXPR_OFFSETOF: {
struct expression *val = copy_expression(C, expr->down);
if (expr->op == '.') {
if (expr->down != val) {
expr = dup_expression(C, expr);
expr->down = val;
}
} else {
struct expression *idx = copy_expression(C, expr->index);
if (expr->down != val || expr->index != idx) {
expr = dup_expression(C, expr);
expr->down = val;
expr->index = idx;
}
}
break;
}
default:
dmrC_warning(C, expr->pos, "trying to copy expression type %d", expr->type);
}
return expr;
}
static struct expression_list *copy_asm_constraints(struct dmr_C *C, struct expression_list *in)
{
struct expression_list *out = NULL;
struct expression *expr;
int state = 0;
FOR_EACH_PTR(in, expr) {
switch (state) {
case 0: /* identifier */
case 1: /* constraint */
state++;
dmrC_add_expression(C, &out, expr);
continue;
case 2: /* expression */
state = 0;
dmrC_add_expression(C, &out, copy_expression(C, expr));
continue;
}
} END_FOR_EACH_PTR(expr);
return out;
}
static void set_replace(struct dmr_C *C, struct symbol *old, struct symbol *news)
{
news->replace = old;
old->replace = news;
}
static void unset_replace(struct dmr_C *C, struct symbol *sym)
{
struct symbol *r = sym->replace;
if (!r) {
dmrC_warning(C, sym->pos, "symbol '%s' not replaced?", dmrC_show_ident(C, sym->ident));
return;
}
r->replace = NULL;
sym->replace = NULL;
}
static void unset_replace_list(struct dmr_C *C, struct symbol_list *list)
{
struct symbol *sym;
FOR_EACH_PTR(list, sym) {
unset_replace(C, sym);
} END_FOR_EACH_PTR(sym);
}
static struct statement *copy_one_statement(struct dmr_C *C, struct statement *stmt)
{
if (!stmt)
return NULL;
switch(stmt->type) {
case STMT_NONE:
break;
case STMT_DECLARATION: {
struct symbol *sym;
struct statement *newstmt = dup_statement(C, stmt);
newstmt->declaration = NULL;
FOR_EACH_PTR(stmt->declaration, sym) {
struct symbol *newsym = copy_symbol(C, stmt->pos, sym);
if (newsym != sym)
newsym->initializer = copy_expression(C, sym->initializer);
dmrC_add_symbol(C, &newstmt->declaration, newsym);
} END_FOR_EACH_PTR(sym);
stmt = newstmt;
break;
}
case STMT_CONTEXT:
case STMT_EXPRESSION: {
struct expression *expr = copy_expression(C, stmt->expression);
if (expr == stmt->expression)
break;
stmt = dup_statement(C, stmt);
stmt->expression = expr;
break;
}
case STMT_RANGE: {
struct expression *expr = copy_expression(C, stmt->range_expression);
if (expr == stmt->expression)
break;
stmt = dup_statement(C, stmt);
stmt->range_expression = expr;
break;
}
case STMT_COMPOUND: {
struct statement *newst = dmrC_alloc_statement(C, stmt->pos, STMT_COMPOUND);
dmrC_copy_statement(C, stmt, newst);
stmt = newst;
break;
}
case STMT_IF: {
struct expression *cond = stmt->if_conditional;
struct statement *trues = stmt->if_true;
struct statement *falses = stmt->if_false;
cond = copy_expression(C, cond);
trues = copy_one_statement(C, trues);
falses = copy_one_statement(C, falses);
if (stmt->if_conditional == cond &&
stmt->if_true == trues &&
stmt->if_false == falses)
break;
stmt = dup_statement(C, stmt);
stmt->if_conditional = cond;
stmt->if_true = trues;
stmt->if_false = falses;
break;
}
case STMT_RETURN: {
struct expression *retval = copy_expression(C, stmt->ret_value);
struct symbol *sym = copy_symbol(C, stmt->pos, stmt->ret_target);
stmt = dup_statement(C, stmt);
stmt->ret_value = retval;
stmt->ret_target = sym;
break;
}
case STMT_CASE: {
stmt = dup_statement(C, stmt);
stmt->case_label = copy_symbol(C, stmt->pos, stmt->case_label);
stmt->case_label->stmt = stmt;
stmt->case_expression = copy_expression(C, stmt->case_expression);
stmt->case_to = copy_expression(C, stmt->case_to);
stmt->case_statement = copy_one_statement(C, stmt->case_statement);
break;
}
case STMT_SWITCH: {
struct symbol *switch_break = copy_symbol(C, stmt->pos, stmt->switch_break);
struct symbol *switch_case = copy_symbol(C, stmt->pos, stmt->switch_case);
struct expression *expr = copy_expression(C, stmt->switch_expression);
struct statement *switch_stmt = copy_one_statement(C, stmt->switch_statement);
stmt = dup_statement(C, stmt);
switch_case->symbol_list = copy_symbol_list(C, switch_case->symbol_list);
stmt->switch_break = switch_break;
stmt->switch_case = switch_case;
stmt->switch_expression = expr;
stmt->switch_statement = switch_stmt;
break;
}
case STMT_ITERATOR: {
stmt = dup_statement(C, stmt);
stmt->iterator_break = copy_symbol(C, stmt->pos, stmt->iterator_break);
stmt->iterator_continue = copy_symbol(C, stmt->pos, stmt->iterator_continue);
stmt->iterator_syms = copy_symbol_list(C, stmt->iterator_syms);
stmt->iterator_pre_statement = copy_one_statement(C, stmt->iterator_pre_statement);
stmt->iterator_pre_condition = copy_expression(C, stmt->iterator_pre_condition);
stmt->iterator_statement = copy_one_statement(C, stmt->iterator_statement);
stmt->iterator_post_statement = copy_one_statement(C, stmt->iterator_post_statement);
stmt->iterator_post_condition = copy_expression(C, stmt->iterator_post_condition);
break;
}
case STMT_LABEL: {
stmt = dup_statement(C, stmt);
stmt->label_identifier = copy_symbol(C, stmt->pos, stmt->label_identifier);
stmt->label_statement = copy_one_statement(C, stmt->label_statement);
break;
}
case STMT_GOTO: {
stmt = dup_statement(C, stmt);
stmt->goto_label = copy_symbol(C, stmt->pos, stmt->goto_label);
stmt->goto_expression = copy_expression(C, stmt->goto_expression);
stmt->target_list = copy_symbol_list(C, stmt->target_list);
break;
}
case STMT_ASM: {
stmt = dup_statement(C, stmt);
stmt->asm_inputs = copy_asm_constraints(C, stmt->asm_inputs);
stmt->asm_outputs = copy_asm_constraints(C, stmt->asm_outputs);
/* no need to dup "clobbers", since they are all constant strings */
break;
}
default:
dmrC_warning(C, stmt->pos, "trying to copy statement type %d", stmt->type);
break;
}
return stmt;
}
/*
* Copy a statement tree from 'src' to 'dst', where both
* source and destination are of type STMT_COMPOUND.
*
* We do this for the tree-level inliner.
*
* This doesn't do the symbol replacement right: it's not
* re-entrant.
*/
void dmrC_copy_statement(struct dmr_C *C, struct statement *src, struct statement *dst)
{
struct statement *stmt;
FOR_EACH_PTR(src->stmts, stmt) {
dmrC_add_statement(C, &dst->stmts, copy_one_statement(C, stmt));
} END_FOR_EACH_PTR(stmt);
dst->args = copy_one_statement(C, src->args);
dst->ret = copy_symbol(C, src->pos, src->ret);
dst->inline_fn = src->inline_fn;
}
static struct symbol *create_copy_symbol(struct dmr_C *C, struct symbol *orig)
{
struct symbol *sym = orig;
if (orig) {
sym = dmrC_alloc_symbol(C->S, orig->pos, orig->type);
*sym = *orig;
sym->bb_target = NULL;
sym->pseudo = NULL;
set_replace(C, orig, sym);
orig = sym;
}
return orig;
}
static struct symbol_list *create_symbol_list(struct dmr_C *C, struct symbol_list *src)
{
struct symbol_list *dst = NULL;
struct symbol *sym;
FOR_EACH_PTR(src, sym) {
struct symbol *newsym = create_copy_symbol(C, sym);
dmrC_add_symbol(C, &dst, newsym);
} END_FOR_EACH_PTR(sym);
return dst;
}
int dmrC_inline_function(struct dmr_C *C, struct expression *expr, struct symbol *sym)
{
struct symbol_list * fn_symbol_list;
struct symbol *fn = sym->ctype.base_type;
struct expression_list *arg_list = expr->args;
struct statement *stmt = dmrC_alloc_statement(C, expr->pos, STMT_COMPOUND);
struct symbol_list *name_list, *arg_decl;
struct symbol *name;
struct expression *arg;
if (!fn->inline_stmt) {
dmrC_sparse_error(C, fn->pos, "marked inline, but without a definition");
return 0;
}
if (fn->expanding)
return 0;
fn->expanding = 1;
name_list = fn->arguments;
expr->type = EXPR_STATEMENT;
expr->statement = stmt;
expr->ctype = fn->ctype.base_type;
fn_symbol_list = create_symbol_list(C, sym->inline_symbol_list);
arg_decl = NULL;
PREPARE_PTR_LIST(name_list, name);
FOR_EACH_PTR(arg_list, arg) {
struct symbol *a = dmrC_alloc_symbol(C->S, arg->pos, SYM_NODE);
a->ctype.base_type = arg->ctype;
if (name) {
*a = *name;
set_replace(C, name, a);
dmrC_add_symbol(C, &fn_symbol_list, a);
}
a->initializer = arg;
dmrC_add_symbol(C, &arg_decl, a);
NEXT_PTR_LIST(name);
} END_FOR_EACH_PTR(arg);
FINISH_PTR_LIST(name);
dmrC_copy_statement(C, fn->inline_stmt, stmt);
if (arg_decl) {
struct statement *decl = dmrC_alloc_statement(C, expr->pos, STMT_DECLARATION);
decl->declaration = arg_decl;
stmt->args = decl;
}
stmt->inline_fn = sym;
unset_replace_list(C, fn_symbol_list);
dmrC_evaluate_statement(C, stmt);
fn->expanding = 0;
return 1;
}
void dmrC_uninline(struct dmr_C *C, struct symbol *sym)
{
struct symbol *fn = sym->ctype.base_type;
struct symbol_list *arg_list = fn->arguments;
struct symbol *p;
sym->symbol_list = create_symbol_list(C, sym->inline_symbol_list);
FOR_EACH_PTR(arg_list, p) {
p->replace = p;
} END_FOR_EACH_PTR(p);
fn->stmt = dmrC_alloc_statement(C, fn->pos, STMT_COMPOUND);
dmrC_copy_statement(C, fn->inline_stmt, fn->stmt);
unset_replace_list(C, sym->symbol_list);
unset_replace_list(C, arg_list);
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,299 @@
#ifndef DMR_LIB_H
#define DMR_LIB_H
/* This file is derived from lib.h in sparse */
#include <stddef.h>
#include <stdlib.h>
#include <time.h>
/*
* Basic helper routine descriptions for 'sparse'.
*
* Copyright (C) 2003 Transmeta Corp.
* 2003 Linus Torvalds
* 2004 Christopher Li
*
* 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.
*/
/*
* This version is part of the dmr_c project.
* Copyright (C) 2017 Dibyendu Majumdar
*/
// Build options
#define NEW_SSA 0
#define SINGLE_STORE_SHORTCUT 1
#include <allocate.h>
#include <ptrlist.h>
#ifdef __cplusplus
extern "C" {
#endif
#define DO_STRINGIFY(x) #x
#define STRINGIFY(x) DO_STRINGIFY(x)
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#endif
#define MAX_STRING 8191
extern unsigned int dmrC_hexval(unsigned int c);
struct position {
unsigned int type : 6,
stream : 14,
newline : 1,
whitespace : 1,
pos : 10;
unsigned int line : 31,
noexpand : 1;
};
struct ident;
struct token;
struct symbol;
struct statement;
struct expression;
struct basic_block;
struct entrypoint;
struct instruction;
struct multijmp;
struct pseudo;
struct string;
typedef struct pseudo *pseudo_t;
struct target_t;
struct global_symbols_t;
struct tokenizer_state_t;
struct linearizer_state_t;
struct warning {
const char *name;
int *flag;
};
enum standard {
STANDARD_C89,
STANDARD_C94,
STANDARD_C99,
STANDARD_C11,
STANDARD_GNU11,
STANDARD_GNU89,
STANDARD_GNU99,
};
enum {
WARNING_OFF,
WARNING_ON,
WARNING_FORCE_OFF
};
struct symbol_list;
struct statement_list;
struct expression_list;
struct basic_block_list;
struct instruction_list;
struct multijmp_list;
struct pseudo_list;
struct phi_map;
DECLARE_PTR_LIST(string_list, char);
#define ERROR_CURR_PHASE (1 << 0)
#define ERROR_PREV_PHASE (1 << 1)
struct dmr_C {
struct target_t *target;
struct global_symbols_t *S;
struct tokenizer_state_t *T;
struct parse_state_t *P;
struct linearizer_state_t *L;
void *User_data;
// memory allocators
struct allocator ptrlist_allocator;
struct allocator token_allocator;
struct allocator protected_token_allocator;
struct allocator byte_allocator;
struct allocator string_allocator;
struct allocator ident_allocator;
struct allocator scope_allocator;
struct allocator expression_allocator;
struct allocator statement_allocator;
int max_warnings;
int show_info;
int errors;
int die_if_error;
int once;
int preprocess_only;
int codegen;
int has_error;
const char *gcc_base_dir;
const char *multiarch_dir;
int verbose, optimize, optimize_size, preprocessing;
enum standard standard;
struct token *pre_buffer_begin;
struct token *pre_buffer_end;
int Waddress; // TODO
int Waddress_space;
int Wbitwise;
int Wcast_to_as;
int Wcast_truncate;
int Wcontext;
int Wdecl;
int Wdeclarationafterstatement;
int Wdefault_bitfield_sign;
int Wdesignated_init;
int Wdo_while;
int Wenum_mismatch;
int Wsparse_error;
int Winit_cstring;
int Wmemcpy_max_count; // TODO
int Wnon_pointer_null;
int Wold_initializer;
int Wone_bit_signed_bitfield;
int Woverride_init; //TODO
int Woverride_init_all; //TODO
int Woverride_init_whole_range; //TODO
int Wparen_string;
int Wptr_subtraction_blows;
int Wreturn_void;
int Wshadow;
int Wsizeof_bool;
int Wtautological_compare;
int Wtransparent_union;
int Wtypesign;
int Wundef;
int Wuninitialized;
int Wunknown_attribute;
int Wvla;
struct warning warnings[32];
struct warning debugs[2];
struct warning dumps[1];
#define CMDLINE_INCLUDE 20
int cmdline_include_nr;
char *cmdline_include[CMDLINE_INCLUDE];
int dump_macro_defs; // TODO
int dbg_entry;
int dbg_dead;
int fmem_report; // TODO
int fdump_linearize; // TODO
unsigned long long fmemcpy_max_count;
int arch_m64;
int arch_msize_long;
int arch_big_endian; // TODO
/* TODO is this the right place? */
struct scope *block_scope, *function_scope, *file_scope, *global_scope;
struct scope *builtin_scope;
/* Current parsing/evaluation function */
struct symbol *current_fn;
char modifier_string_buffer[100];
char typename_array[200];
struct ident_list *macros; // only needed for -dD
int false_nesting;
int counter_macro; // __COUNTER__ expansion
#define INCLUDEPATHS 300
const char *includepath[INCLUDEPATHS + 1];
const char **quote_includepath;
const char **angle_includepath;
const char **isys_includepath;
const char **sys_includepath;
const char **dirafter_includepath;
char date_buffer[12]; /* __DATE__: 3 + ' ' + 2 + ' ' + 4 + '\0' */
char preprocessor_buffer[MAX_STRING];
char preprocessor_mergebuffer[512];
char preprocessor_tokenseqbuffer[256];
time_t t;
char fullname[1024];
char output_file_name[1024];
};
/*
* Creates a new instance of dmr_C. Due to the way the parser and compiler works
* at present it is recommended that each dmr_C instance be used to process one set
* of inputs only. Destroy the dmr_C instance after use. This way all resources will
* be released.
*/
extern struct dmr_C *new_dmr_C();
extern void destroy_dmr_C(struct dmr_C *C);
/*
* Appends the provided formatted string to the "pre buffer" that is processed by
* dmrC_sparse_initialize(). The input is tokenized immediately and added to the "pre buffer"
* token stream.
*/
extern void dmrC_add_pre_buffer(struct dmr_C *, const char *fmt, ...) FORMAT_ATTR(2);
/*
* Declares a bunch of gcc built-ins into a "pre buffer" which is processed in
* dmrC_sparse_initialize(). The dmrC_add_pre_buffer() function is used to add input into the
* pre buffer.
*/
extern void dmrC_declare_builtin_functions(struct dmr_C *C);
extern void dmrC_create_builtin_stream(struct dmr_C *C);
extern void dmrC_dump_macro_definitions(struct dmr_C *C);
extern struct symbol_list * dmrC_sparse_initialize(struct dmr_C *C, int argc, char **argv, struct string_list **filelist);
extern struct symbol_list * dmrC_sparse_keep_tokens(struct dmr_C *C, char *filename);
extern struct symbol_list * dmrC_sparse(struct dmr_C *C, char *filename);
extern struct symbol_list * dmrC__sparse(struct dmr_C *C, char *filename);
extern struct symbol_list * dmrC_sparse_buffer(struct dmr_C *C, const char *name, char *buffer, int keep_tokens);
struct token *dmrC_skip_to_token(struct token *, int);
struct token *dmrC_expect_token(struct dmr_C *C, struct token *token, int op, const char *where);
extern void dmrC_die(struct dmr_C *, const char *, ...) FORMAT_ATTR(2) NORETURN_ATTR;
extern void dmrC_info(struct dmr_C *, struct position, const char *, ...)
FORMAT_ATTR(3);
extern void dmrC_warning(struct dmr_C *, struct position, const char *, ...)
FORMAT_ATTR(3);
extern void dmrC_sparse_error(struct dmr_C *, struct position, const char *, ...)
FORMAT_ATTR(3);
extern void dmrC_error_die(struct dmr_C *, struct position, const char *, ...)
FORMAT_ATTR(3) NORETURN_ATTR;
extern void dmrC_expression_error(struct dmr_C *, struct expression *, const char *,
...) FORMAT_ATTR(3);
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

@ -0,0 +1,481 @@
#ifndef DMR_C_LINEARIZE_H
#define DMR_C_LINEARIZE_H
/*
* Linearize - walk the parse tree and generate a linear version
* of it and the basic blocks.
*
* Copyright (C) 2004 Linus Torvalds
* Copyright (C) 2004 Christopher Li
*/
#include <lib.h>
#include <allocate.h>
#include <token.h>
#include <parse.h>
#include <symbol.h>
#ifdef __cplusplus
extern "C" {
#endif
struct instruction;
DECLARE_PTR_LIST(basic_block_list, struct basic_block);
DECLARE_PTR_LIST(instruction_list, struct instruction);
DECLARE_PTR_LIST(multijmp_list, struct multijmp);
DECLARE_PTR_LIST(pseudo_list, struct pseudo);
struct pseudo_user {
struct instruction *insn;
pseudo_t *userp;
};
DECLARE_PTR_LIST(pseudo_user_list, struct pseudo_user);
enum pseudo_type {
PSEUDO_VOID,
PSEUDO_REG,
PSEUDO_SYM,
PSEUDO_VAL,
PSEUDO_ARG,
PSEUDO_PHI,
};
/* Have you ever heard of "static single assignment" or SSA form?
struct pseudo represents one of those single-assignment variables.
Each one has a pointer to the symbol it represents (which may
have many pseudos referencing it). Each one also has a pointer
to the instruction that defines it.*/
struct pseudo {
int nr;
enum pseudo_type type;
int size; /* OP_SETVAL only */
struct pseudo_user_list *users; /* pseudo_user list */
struct ident *ident;
union {
struct symbol *sym; // PSEUDO_SYM, VAL & ARG
struct instruction *def; // PSEUDO_REG & PHI
long long value; // PSEUDO_VAL
};
DMRC_BACKEND_TYPE priv;
DMRC_BACKEND_TYPE priv2; /* FIXME - we use this to save ptr to allocated stack in PHI instructions (nanojit) */
};
struct linearizer_state_t {
struct allocator pseudo_allocator;
struct allocator pseudo_user_allocator;
struct allocator asm_constraint_allocator;
struct allocator asm_rules_allocator;
struct allocator multijmp_allocator;
struct allocator basic_block_allocator;
struct allocator entrypoint_allocator;
struct allocator instruction_allocator;
struct pseudo void_pseudo;
struct position current_pos;
int repeat_phase;
unsigned long bb_generation;
int liveness_changed;
struct pseudo_list **live_list;
struct pseudo_list *dead_list;
#define MAX_VAL_HASH 64
struct pseudo_list *prev[MAX_VAL_HASH]; /* from pseudo_t value_pseudo(long long val) in linearize.c */
int nr; /* pseudo number */
int bb_nr; /* basic block number */
char buffer[4096*4];
int n;
char pseudo_buffer[4][64];
#define INSN_HASH_SIZE 256
struct instruction_list *insn_hash_table[INSN_HASH_SIZE];
};
#define VOID_PSEUDO(C) (&C->L->void_pseudo)
struct multijmp {
struct basic_block *target;
long long begin, end;
};
struct asm_constraint {
pseudo_t pseudo;
const char *constraint;
const struct ident *ident;
};
DECLARE_PTR_LIST(asm_constraint_list, struct asm_constraint);
struct asm_rules {
struct asm_constraint_list *inputs; /* list of asm_constraint */
struct asm_constraint_list *outputs; /* list of asm_constraint */
struct asm_constraint_list *clobbers; /* list of asm_constraint */
};
struct instruction {
unsigned opcode:8,
size:24;
struct basic_block *bb;
struct position pos;
struct symbol *type;
union {
pseudo_t target;
pseudo_t cond; /* for branch and switch */
};
union {
struct /* entrypoint */ {
struct pseudo_list *arg_list; /* pseudo list */
};
struct /* branch */ {
struct basic_block *bb_true, *bb_false;
};
struct /* switch */ {
struct multijmp_list *multijmp_list;
};
struct /* phi_node */ {
struct pseudo_list *phi_list; /* pseudo list */
};
struct /* phi source */ {
pseudo_t phi_src;
struct instruction_list *phi_users; /* instruction list */
};
struct /* unops */ {
pseudo_t src;
struct symbol *orig_type; /* casts */
unsigned int offset; /* memops */
};
struct /* binops and sel */ {
pseudo_t src1, src2, src3;
};
struct /* slice */ {
pseudo_t base;
unsigned from, len;
};
struct /* setval */ {
pseudo_t symbol; /* Subtle: same offset as "src" !! */
struct expression *val;
};
struct /* call */ {
pseudo_t func;
struct pseudo_list *arguments; /* instruction list */
struct symbol *fntype;
};
struct /* context */ {
int increment;
int check;
struct expression *context_expr;
};
struct /* asm */ {
const char *string;
struct asm_rules *asm_rules;
};
};
};
enum opcode {
OP_BADOP,
/* Entry */
OP_ENTRY,
/* Terminator */
OP_TERMINATOR,
OP_RET = OP_TERMINATOR,
OP_BR,
OP_CBR,
OP_SWITCH,
OP_INVOKE,
OP_COMPUTEDGOTO,
OP_UNWIND,
OP_TERMINATOR_END = OP_UNWIND,
/* Binary */
OP_BINARY,
OP_ADD = OP_BINARY,
OP_SUB,
OP_MULU, OP_MULS,
OP_DIVU, OP_DIVS,
OP_MODU, OP_MODS,
OP_SHL,
OP_LSR, OP_ASR,
/* Logical */
OP_AND,
OP_OR,
OP_XOR,
OP_AND_BOOL,
OP_OR_BOOL,
OP_BINARY_END = OP_OR_BOOL,
/* Binary comparison */
OP_BINCMP,
OP_SET_EQ = OP_BINCMP,
OP_SET_NE,
OP_SET_LE,
OP_SET_GE,
OP_SET_LT,
OP_SET_GT,
OP_SET_B,
OP_SET_A,
OP_SET_BE,
OP_SET_AE,
OP_BINCMP_END = OP_SET_AE,
/* Uni */
OP_NOT,
OP_NEG,
/* Select - three input values */
OP_SEL,
/* Memory */
OP_MALLOC,
OP_FREE,
OP_ALLOCA,
OP_LOAD,
OP_STORE,
OP_SETVAL,
OP_SYMADDR,
OP_GET_ELEMENT_PTR,
/* Other */
OP_PHI,
OP_PHISOURCE,
OP_CAST,
OP_SCAST,
OP_FPCAST,
OP_PTRCAST,
OP_INLINED_CALL,
OP_CALL,
OP_VANEXT,
OP_VAARG,
OP_SLICE,
OP_SNOP,
OP_LNOP,
OP_NOP,
OP_DEATHNOTE,
OP_ASM,
/* Sparse tagging (line numbers, context, whatever) */
OP_CONTEXT,
OP_RANGE,
/* Needed to translate SSA back to normal form */
OP_COPY,
};
/*
A basic block represents a series of instructions with no branches.
Straight-line code. A branch only occurs at the end of a basic block,
and branches can only target the beginning of a basic block. Typically,
a conditional will consist of a basic block leading up to the branch,
a basic block for the true case, a basic block for the false case,
and a basic block where the two paths merge back together. Either the true
or the false case may not exist. A loop will normally have a basic block
for the loop body, which can branch to the top at the end or continue
to the next basic block. So basic blocks represent a node in the control
flow graph. The edges in that graph lead from one basic block to a
basic block which can follow it in the execution of the program.
*/
struct basic_block {
struct position pos;
unsigned long generation;
int context;
struct entrypoint *ep;
struct basic_block_list *parents; /* basic_block sources */ /* predecessors */
struct basic_block_list *children; /* basic_block destinations */ /* successors */
struct instruction_list *insns; /* Linear list of instructions */
struct pseudo_list *needs, *defines; /* pseudo lists */
/* TODO Following fields are used by the codegen backends.
In Sparse this is a union but we need the nr field
for NanoJIT backend's liveness analysis in addition to
creating unique labels.
*/
//union {
unsigned int nr; /* unique id for label's names */
DMRC_BACKEND_TYPE priv;
//};
};
static inline int dmrC_instruction_list_size(struct instruction_list *list)
{
return ptrlist_size((struct ptr_list *)list);
}
static inline int dmrC_pseudo_list_size(struct pseudo_list *list)
{
return ptrlist_size((struct ptr_list *)list);
}
static inline int dmrC_bb_list_size(struct basic_block_list *list)
{
return ptrlist_size((struct ptr_list *)list);
}
static inline void dmrC_free_instruction_list(struct pseudo_list **head)
{
ptrlist_remove_all((struct ptr_list **)head);
}
static inline struct instruction * dmrC_delete_last_instruction(struct instruction_list **head)
{
return (struct instruction *) ptrlist_undo_last((struct ptr_list **)head);
}
static inline struct basic_block * dmrC_delete_last_basic_block(struct basic_block_list **head)
{
return (struct basic_block *) ptrlist_delete_last((struct ptr_list **)head);
}
static inline struct basic_block *dmrC_first_basic_block(struct basic_block_list *head)
{
return (struct basic_block *) ptrlist_first((struct ptr_list *)head);
}
static inline struct instruction *dmrC_last_instruction(struct instruction_list *head)
{
return (struct instruction *) ptrlist_last((struct ptr_list *)head);
}
static inline struct instruction *dmrC_first_instruction(struct instruction_list *head)
{
return (struct instruction *) ptrlist_first((struct ptr_list *)head);
}
static inline pseudo_t dmrC_first_pseudo(struct pseudo_list *head)
{
return (pseudo_t) ptrlist_first((struct ptr_list *)head);
}
static inline void dmrC_concat_basic_block_list(struct basic_block_list *from, struct basic_block_list **to)
{
ptrlist_concat((struct ptr_list *)from, (struct ptr_list **)to);
}
static inline void dmrC_concat_instruction_list(struct instruction_list *from, struct instruction_list **to)
{
ptrlist_concat((struct ptr_list *)from, (struct ptr_list **)to);
}
static inline int dmrC_is_branch_goto(struct instruction *br)
{
return br && br->opcode==OP_BR && (!br->bb_true || !br->bb_false);
}
static inline void dmrC_add_bb(struct dmr_C *C, struct basic_block_list **list, struct basic_block *bb)
{
ptrlist_add((struct ptr_list **)list, bb, &C->ptrlist_allocator);
}
static inline void dmrC_add_instruction(struct dmr_C *C, struct instruction_list **list, struct instruction *insn)
{
ptrlist_add((struct ptr_list **)list, insn, &C->ptrlist_allocator);
}
static inline void dmrC_add_multijmp(struct dmr_C *C, struct multijmp_list **list, struct multijmp *multijmp)
{
ptrlist_add((struct ptr_list **)list, multijmp, &C->ptrlist_allocator);
}
static inline pseudo_t *dmrC_add_pseudo(struct dmr_C *C, struct pseudo_list **list, pseudo_t pseudo)
{
return (pseudo_t *) ptrlist_add((struct ptr_list **)list, pseudo, &C->ptrlist_allocator);
}
static inline int dmrC_remove_pseudo(struct pseudo_list **list, pseudo_t pseudo)
{
return ptrlist_remove((struct ptr_list **)list, pseudo, 0) != 0;
}
static inline int dmrC_bb_terminated(struct basic_block *bb)
{
struct instruction *insn;
if (!bb)
return 0;
insn = dmrC_last_instruction(bb->insns);
return insn && insn->opcode >= OP_TERMINATOR
&& insn->opcode <= OP_TERMINATOR_END;
}
static inline int dmrC_bb_reachable(struct basic_block *bb)
{
return bb != NULL;
}
static inline void dmrC_add_pseudo_user_ptr(struct dmr_C *C, struct pseudo_user *user, struct pseudo_user_list **list)
{
ptrlist_add((struct ptr_list **)list, user, &C->ptrlist_allocator);
}
static inline int dmrC_has_use_list(pseudo_t p)
{
return (p && p->type != PSEUDO_VOID && p->type != PSEUDO_VAL);
}
static inline struct pseudo_user *dmrC_alloc_pseudo_user(struct dmr_C *C, struct instruction *insn, pseudo_t *pp)
{
struct pseudo_user *user = (struct pseudo_user *) dmrC_allocator_allocate(&C->L->pseudo_user_allocator, 0);
user->userp = pp;
user->insn = insn;
return user;
}
static inline void dmrC_use_pseudo(struct dmr_C *C, struct instruction *insn, pseudo_t p, pseudo_t *pp)
{
*pp = p;
if (dmrC_has_use_list(p))
dmrC_add_pseudo_user_ptr(C, dmrC_alloc_pseudo_user(C, insn, pp), &p->users);
}
static inline void dmrC_remove_bb_from_list(struct basic_block_list **list, struct basic_block *entry, int count)
{
ptrlist_remove((struct ptr_list **)list, entry, count);
}
static inline void dmrC_replace_bb_in_list(struct basic_block_list **list,
struct basic_block *old, struct basic_block *newbb, int count)
{
ptrlist_replace((struct ptr_list **)list, old, newbb, count);
}
struct entrypoint {
struct symbol *name;
struct symbol_list *syms; /* symbol list */
struct pseudo_list *accesses; /* pseudo list */
struct basic_block_list *bbs; /* basic_block list */
struct basic_block *active;
struct instruction *entry;
};
extern void dmrC_insert_select(struct dmr_C *C, struct basic_block *bb, struct instruction *br, struct instruction *phi, pseudo_t if_true, pseudo_t if_false);
extern void dmrC_insert_branch(struct dmr_C *C, struct basic_block *bb, struct instruction *br, struct basic_block *target);
// From Luc: sssa-mini
struct instruction *dmrC_alloc_phisrc(struct dmr_C *C, pseudo_t pseudo, struct symbol *type);
pseudo_t dmrC_insert_phi_node(struct dmr_C *C, struct basic_block *bb, struct symbol *type);
pseudo_t dmrC_alloc_phi(struct dmr_C *C, struct basic_block *source, pseudo_t pseudo, struct symbol *type);
pseudo_t dmrC_alloc_pseudo(struct dmr_C *C, struct instruction *def);
pseudo_t dmrC_value_pseudo(struct dmr_C *C, struct symbol *type, long long val);
unsigned int dmrC_value_size(long long value);
struct entrypoint *dmrC_linearize_symbol(struct dmr_C *C, struct symbol *sym);
int dmrC_unssa(struct dmr_C *C, struct entrypoint *ep);
void dmrC_show_entry(struct dmr_C *C, struct entrypoint *ep);
const char *dmrC_show_pseudo(struct dmr_C *C, pseudo_t pseudo);
void dmrC_show_bb(struct dmr_C *C, struct basic_block *bb);
const char *dmrC_show_instruction(struct dmr_C *C, struct instruction *insn);
void dmrC_init_linearizer(struct dmr_C *C);
void dmrC_destroy_linearizer(struct dmr_C *C);
#define dmrC_hashval(x) ((unsigned long)(((uintptr_t)(x))))
#ifdef __cplusplus
}
#endif
#endif /* LINEARIZE_H */

@ -0,0 +1,379 @@
/*
* Register - track pseudo usage, maybe eventually try to do register
* allocation.
*
* Copyright (C) 2004 Linus Torvalds
*/
#include <assert.h>
#include <port.h>
#include <parse.h>
#include <expression.h>
#include <linearize.h>
#include <flow.h>
static void phi_defines(struct dmr_C *C, struct instruction * phi_node, pseudo_t target,
void (*defines)(struct dmr_C *C, struct basic_block *, pseudo_t))
{
pseudo_t phi;
FOR_EACH_PTR(phi_node->phi_list, phi) {
struct instruction *def;
if (phi == VOID_PSEUDO(C))
continue;
def = phi->def;
if (!def || !def->bb)
continue;
defines(C, def->bb, target);
} END_FOR_EACH_PTR(phi);
}
static void asm_liveness(struct dmr_C *C, struct basic_block *bb, struct instruction *insn,
void (*def)(struct dmr_C *C, struct basic_block *, pseudo_t),
void (*use)(struct dmr_C *C, struct basic_block *, pseudo_t))
{
struct asm_constraint *entry;
FOR_EACH_PTR(insn->asm_rules->inputs, entry) {
use(C, bb, entry->pseudo);
} END_FOR_EACH_PTR(entry);
FOR_EACH_PTR(insn->asm_rules->outputs, entry) {
def(C, bb, entry->pseudo);
} END_FOR_EACH_PTR(entry);
}
static void track_instruction_usage(struct dmr_C *C, struct basic_block *bb, struct instruction *insn,
void (*def)(struct dmr_C *C, struct basic_block *, pseudo_t),
void (*use)(struct dmr_C *C, struct basic_block *, pseudo_t))
{
#define USES(x) use(C, bb, insn->x)
#define DEFINES(x) def(C, bb, insn->x)
switch (insn->opcode) {
case OP_RET:
USES(src);
break;
case OP_CBR:
case OP_SWITCH:
USES(cond);
break;
case OP_COMPUTEDGOTO:
USES(target);
break;
/* Binary */
case OP_ADD:
case OP_SUB:
case OP_MULU:
case OP_MULS:
case OP_DIVU:
case OP_DIVS:
case OP_MODU:
case OP_MODS:
case OP_SHL:
case OP_LSR:
case OP_ASR:
case OP_AND:
case OP_OR:
case OP_XOR:
case OP_AND_BOOL:
case OP_OR_BOOL:
case OP_SET_EQ:
case OP_SET_NE:
case OP_SET_LE:
case OP_SET_GE:
case OP_SET_LT:
case OP_SET_GT:
case OP_SET_B:
case OP_SET_A:
case OP_SET_BE:
case OP_SET_AE:
USES(src1); USES(src2); DEFINES(target);
break;
/* Uni */
case OP_NOT: case OP_NEG:
USES(src1); DEFINES(target);
break;
case OP_SEL:
USES(src1); USES(src2); USES(src3); DEFINES(target);
break;
/* Memory */
case OP_LOAD:
USES(src); DEFINES(target);
break;
case OP_STORE:
USES(src); USES(target);
break;
case OP_SETVAL:
DEFINES(target);
break;
case OP_SYMADDR:
USES(symbol); DEFINES(target);
break;
/* Other */
case OP_PHI:
/* Phi-nodes are "backwards" nodes. Their def doesn't matter */
phi_defines(C, insn, insn->target, def);
break;
case OP_PHISOURCE:
/*
* We don't care about the phi-source define, they get set
* up and expanded by the OP_PHI
*/
USES(phi_src);
break;
case OP_CAST:
case OP_SCAST:
case OP_FPCAST:
case OP_PTRCAST:
USES(src); DEFINES(target);
break;
case OP_CALL: {
pseudo_t arg;
USES(func);
if (insn->target != VOID_PSEUDO(C))
DEFINES(target);
FOR_EACH_PTR(insn->arguments, arg) {
use(C, bb, arg);
} END_FOR_EACH_PTR(arg);
break;
}
case OP_SLICE:
USES(base); DEFINES(target);
break;
case OP_ASM:
asm_liveness(C, bb, insn, def, use);
break;
case OP_RANGE:
USES(src1); USES(src2); USES(src3);
break;
case OP_BADOP:
case OP_INVOKE:
case OP_UNWIND:
case OP_MALLOC:
case OP_FREE:
case OP_ALLOCA:
case OP_GET_ELEMENT_PTR:
case OP_VANEXT:
case OP_VAARG:
case OP_SNOP:
case OP_LNOP:
case OP_NOP:
case OP_CONTEXT:
break;
}
}
int dmrC_pseudo_in_list(struct pseudo_list *list, pseudo_t pseudo)
{
pseudo_t old;
FOR_EACH_PTR(list,old) {
if (old == pseudo)
return 1;
} END_FOR_EACH_PTR(old);
return 0;
}
static void add_pseudo_exclusive(struct dmr_C *C, struct pseudo_list **list, pseudo_t pseudo)
{
if (!dmrC_pseudo_in_list(*list, pseudo)) {
C->L->liveness_changed = 1;
dmrC_add_pseudo(C, list, pseudo);
}
}
static inline int trackable_pseudo(pseudo_t pseudo)
{
return pseudo && (pseudo->type == PSEUDO_REG || pseudo->type == PSEUDO_ARG);
}
static void insn_uses(struct dmr_C *C, struct basic_block *bb, pseudo_t pseudo)
{
if (trackable_pseudo(pseudo)) {
struct instruction *def = pseudo->def;
if (pseudo->type != PSEUDO_REG || def->bb != bb || def->opcode == OP_PHI)
add_pseudo_exclusive(C, &bb->needs, pseudo);
}
}
static void insn_defines(struct dmr_C *C, struct basic_block *bb, pseudo_t pseudo)
{
assert(trackable_pseudo(pseudo));
dmrC_add_pseudo(C, &bb->defines, pseudo);
}
static void track_bb_liveness(struct dmr_C *C, struct basic_block *bb)
{
pseudo_t needs;
FOR_EACH_PTR(bb->needs, needs) {
struct basic_block *parent;
FOR_EACH_PTR(bb->parents, parent) {
if (!dmrC_pseudo_in_list(parent->defines, needs)) {
add_pseudo_exclusive(C, &parent->needs, needs);
}
} END_FOR_EACH_PTR(parent);
} END_FOR_EACH_PTR(needs);
}
/*
* We need to clear the liveness information if we
* are going to re-run it.
*/
void dmrC_clear_liveness(struct entrypoint *ep)
{
struct basic_block *bb;
FOR_EACH_PTR(ep->bbs, bb) {
ptrlist_remove_all((struct ptr_list **)&bb->needs);
ptrlist_remove_all((struct ptr_list **)&bb->defines);
} END_FOR_EACH_PTR(bb);
}
/*
* Track inter-bb pseudo liveness. The intra-bb case
* is purely local information.
*/
void dmrC_track_pseudo_liveness(struct dmr_C *C, struct entrypoint *ep)
{
struct basic_block *bb;
/* Add all the bb pseudo usage */
FOR_EACH_PTR(ep->bbs, bb) {
struct instruction *insn;
FOR_EACH_PTR(bb->insns, insn) {
if (!insn->bb)
continue;
assert(insn->bb == bb);
track_instruction_usage(C, bb, insn, insn_defines, insn_uses);
} END_FOR_EACH_PTR(insn);
} END_FOR_EACH_PTR(bb);
/* Calculate liveness.. */
do {
C->L->liveness_changed = 0;
FOR_EACH_PTR_REVERSE(ep->bbs, bb) {
track_bb_liveness(C, bb);
} END_FOR_EACH_PTR_REVERSE(bb);
} while (C->L->liveness_changed);
/* Remove the pseudos from the "defines" list that are used internally */
FOR_EACH_PTR(ep->bbs, bb) {
pseudo_t def;
FOR_EACH_PTR(bb->defines, def) {
struct basic_block *child;
FOR_EACH_PTR(bb->children, child) {
if (dmrC_pseudo_in_list(child->needs, def))
goto is_used;
} END_FOR_EACH_PTR(child);
DELETE_CURRENT_PTR(def);
is_used:
;
} END_FOR_EACH_PTR(def);
ptrlist_pack((struct ptr_list **)&bb->defines);
} END_FOR_EACH_PTR(bb);
}
static void merge_pseudo_list(struct dmr_C *C, struct pseudo_list *src, struct pseudo_list **dest)
{
pseudo_t pseudo;
FOR_EACH_PTR(src, pseudo) {
add_pseudo_exclusive(C, dest, pseudo);
} END_FOR_EACH_PTR(pseudo);
}
void dmrC_track_phi_uses(struct dmr_C *C, struct instruction *insn)
{
pseudo_t phi;
FOR_EACH_PTR(insn->phi_list, phi) {
struct instruction *def;
if (phi == VOID_PSEUDO(C) || !phi->def)
continue;
def = phi->def;
assert(def->opcode == OP_PHISOURCE);
dmrC_add_instruction(C, &def->phi_users, insn);
} END_FOR_EACH_PTR(phi);
}
static void track_bb_phi_uses(struct dmr_C *C, struct basic_block *bb)
{
struct instruction *insn;
FOR_EACH_PTR(bb->insns, insn) {
if (insn->bb && insn->opcode == OP_PHI)
dmrC_track_phi_uses(C, insn);
} END_FOR_EACH_PTR(insn);
}
static void death_def(struct dmr_C *C, struct basic_block *bb, pseudo_t pseudo)
{
}
static void death_use(struct dmr_C *C, struct basic_block *bb, pseudo_t pseudo)
{
if (trackable_pseudo(pseudo) && !dmrC_pseudo_in_list(*C->L->live_list, pseudo)) {
dmrC_add_pseudo(C, &C->L->dead_list, pseudo);
dmrC_add_pseudo(C, C->L->live_list, pseudo);
}
}
static void track_pseudo_death_bb(struct dmr_C *C, struct basic_block *bb)
{
struct pseudo_list *live = NULL;
struct basic_block *child;
struct instruction *insn;
FOR_EACH_PTR(bb->children, child) {
merge_pseudo_list(C, child->needs, &live);
} END_FOR_EACH_PTR(child);
C->L->live_list = &live;
FOR_EACH_PTR_REVERSE(bb->insns, insn) {
if (!insn->bb)
continue;
C->L->dead_list = NULL;
track_instruction_usage(C, bb, insn, death_def, death_use);
if (C->L->dead_list) {
pseudo_t dead;
FOR_EACH_PTR(C->L->dead_list, dead) {
struct instruction *deathnote = dmrC_allocator_allocate(&C->L->instruction_allocator, 0);
deathnote->bb = bb;
deathnote->opcode = OP_DEATHNOTE;
deathnote->target = dead;
INSERT_CURRENT(deathnote, insn);
} END_FOR_EACH_PTR(dead);
ptrlist_remove_all((struct ptr_list **)&C->L->dead_list);
}
} END_FOR_EACH_PTR_REVERSE(insn);
ptrlist_remove_all((struct ptr_list **)&live);
}
void dmrC_track_pseudo_death(struct dmr_C *C, struct entrypoint *ep)
{
struct basic_block *bb;
FOR_EACH_PTR(ep->bbs, bb) {
track_bb_phi_uses(C, bb);
} END_FOR_EACH_PTR(bb);
FOR_EACH_PTR(ep->bbs, bb) {
track_pseudo_death_bb(C, bb);
} END_FOR_EACH_PTR(bb);
}

@ -0,0 +1,196 @@
/*
* memops - try to combine memory ops.
*
* Copyright (C) 2004 Linus Torvalds
*/
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <assert.h>
#include <port.h>
#include <parse.h>
#include <expression.h>
#include <linearize.h>
#include <flow.h>
static int find_dominating_parents(struct dmr_C *C, pseudo_t pseudo, struct instruction *insn,
struct basic_block *bb, unsigned long generation, struct pseudo_list **dominators,
int local)
{
struct basic_block *parent;
FOR_EACH_PTR(bb->parents, parent) {
struct instruction *one;
struct instruction *br;
pseudo_t phi;
FOR_EACH_PTR_REVERSE(parent->insns, one) {
int dominance;
if (!one->bb)
continue;
if (one == insn)
goto no_dominance;
dominance = dmrC_dominates(C, pseudo, insn, one, local);
if (dominance < 0) {
if (one->opcode == OP_LOAD)
continue;
return 0;
}
if (!dominance)
continue;
goto found_dominator;
} END_FOR_EACH_PTR_REVERSE(one);
no_dominance:
if (parent->generation == generation)
continue;
parent->generation = generation;
if (!find_dominating_parents(C, pseudo, insn, parent, generation, dominators, local))
return 0;
continue;
found_dominator:
br = dmrC_delete_last_instruction(&parent->insns);
phi = dmrC_alloc_phi(C, parent, one->target, one->type);
phi->ident = phi->ident ? phi->ident: one->target->ident;
dmrC_add_instruction(C, &parent->insns, br);
dmrC_use_pseudo(C, insn, phi, dmrC_add_pseudo(C, dominators, phi));
} END_FOR_EACH_PTR(parent);
return 1;
}
static int address_taken(pseudo_t pseudo)
{
struct pseudo_user *pu;
FOR_EACH_PTR(pseudo->users, pu) {
struct instruction *insn = pu->insn;
if (insn->bb && (insn->opcode != OP_LOAD && insn->opcode != OP_STORE))
return 1;
} END_FOR_EACH_PTR(pu);
return 0;
}
static int local_pseudo(pseudo_t pseudo)
{
return pseudo->type == PSEUDO_SYM
&& !(pseudo->sym->ctype.modifiers & (MOD_STATIC | MOD_NONLOCAL))
&& !address_taken(pseudo);
}
static void simplify_loads(struct dmr_C *C, struct basic_block *bb)
{
struct instruction *insn;
FOR_EACH_PTR_REVERSE(bb->insns, insn) {
if (!insn->bb)
continue;
if (insn->opcode == OP_LOAD) {
struct instruction *dom;
pseudo_t pseudo = insn->src;
int local = local_pseudo(pseudo);
struct pseudo_list *dominators;
unsigned long generation;
/* Check for illegal offsets.. */
dmrC_check_access(C, insn);
if (insn->type->ctype.modifiers & MOD_VOLATILE)
continue;
RECURSE_PTR_REVERSE(insn, dom) {
int dominance;
if (!dom->bb)
continue;
dominance = dmrC_dominates(C, pseudo, insn, dom, local);
if (dominance) {
/* possible partial dominance? */
if (dominance < 0) {
if (dom->opcode == OP_LOAD)
continue;
goto next_load;
}
/* Yeehaa! Found one! */
dmrC_convert_load_instruction(C, insn, dom->target);
goto next_load;
}
} END_FOR_EACH_PTR_REVERSE(dom);
/* OK, go find the parents */
generation = ++C->L->bb_generation;
bb->generation = generation;
dominators = NULL;
if (find_dominating_parents(C, pseudo, insn, bb, generation, &dominators, local)) {
/* This happens with initial assignments to structures etc.. */
if (!dominators) {
if (local) {
assert(pseudo->type != PSEUDO_ARG);
dmrC_convert_load_instruction(C, insn, dmrC_value_pseudo(C, insn->type, 0));
}
goto next_load;
}
dmrC_rewrite_load_instruction(C, insn, dominators);
}
}
next_load:
/* Do the next one */;
} END_FOR_EACH_PTR_REVERSE(insn);
}
static void kill_store(struct dmr_C *C, struct instruction *insn)
{
if (insn) {
insn->bb = NULL;
insn->opcode = OP_SNOP;
dmrC_kill_use(C, &insn->target);
}
}
static void kill_dominated_stores(struct dmr_C *C, struct basic_block *bb)
{
struct instruction *insn;
FOR_EACH_PTR_REVERSE(bb->insns, insn) {
if (!insn->bb)
continue;
if (insn->opcode == OP_STORE) {
struct instruction *dom;
pseudo_t pseudo = insn->src;
int local = local_pseudo(pseudo);
RECURSE_PTR_REVERSE(insn, dom) {
int dominance;
if (!dom->bb)
continue;
dominance = dmrC_dominates(C, pseudo, insn, dom, local);
if (dominance) {
/* possible partial dominance? */
if (dominance < 0)
goto next_store;
if (dom->opcode == OP_LOAD)
goto next_store;
/* Yeehaa! Found one! */
kill_store(C, dom);
}
} END_FOR_EACH_PTR_REVERSE(dom);
/* OK, we should check the parents now */
}
next_store:
/* Do the next one */;
} END_FOR_EACH_PTR_REVERSE(insn);
}
void dmrC_simplify_memops(struct dmr_C *C, struct entrypoint *ep)
{
struct basic_block *bb;
FOR_EACH_PTR_REVERSE(ep->bbs, bb) {
simplify_loads(C, bb);
} END_FOR_EACH_PTR_REVERSE(bb);
FOR_EACH_PTR_REVERSE(ep->bbs, bb) {
kill_dominated_stores(C, bb);
} END_FOR_EACH_PTR_REVERSE(bb);
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,185 @@
#ifndef DMR_C_PARSE_H
#define DMR_C_PARSE_H
/*
* Basic parsing data structures. Statements and symbols.
*
* Copyright (C) 2003 Transmeta Corp.
* 2003 Linus Torvalds
*
* 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.
*/
/*
* This version is part of the dmr_c project.
* Copyright (C) 2017 Dibyendu Majumdar
*/
#include <lib.h>
#include <symbol.h>
#ifdef __cplusplus
extern "C" {
#endif
enum statement_type {
STMT_NONE,
STMT_DECLARATION,
STMT_EXPRESSION,
STMT_COMPOUND,
STMT_IF,
STMT_RETURN,
STMT_CASE,
STMT_SWITCH,
STMT_ITERATOR,
STMT_LABEL,
STMT_GOTO,
STMT_ASM,
STMT_CONTEXT,
STMT_RANGE,
};
DECLARE_PTR_LIST(statement_list, struct statement);
struct statement {
enum statement_type type;
struct position pos;
union {
struct /* declaration */ {
struct symbol_list *declaration;
};
struct {
struct expression *expression;
struct expression *context;
};
struct /* return_statement */ {
struct expression *ret_value;
struct symbol *ret_target;
};
struct /* if_statement */ {
struct expression *if_conditional;
struct statement *if_true;
struct statement *if_false;
};
struct /* compound_struct */ {
struct statement_list *stmts;
struct symbol *ret;
struct symbol *inline_fn;
struct statement *args;
};
struct /* labeled_struct */ {
struct symbol *label_identifier;
struct statement *label_statement;
};
struct /* case_struct */ {
struct expression *case_expression;
struct expression *case_to;
struct statement *case_statement;
struct symbol *case_label;
};
struct /* switch_struct */ {
struct expression *switch_expression;
struct statement *switch_statement;
struct symbol *switch_break, *switch_case;
};
struct /* iterator_struct */ {
struct symbol *iterator_break;
struct symbol *iterator_continue;
struct symbol_list *iterator_syms;
struct statement *iterator_pre_statement;
struct expression *iterator_pre_condition;
struct statement *iterator_statement;
struct statement *iterator_post_statement;
struct expression *iterator_post_condition;
};
struct /* goto_struct */ {
struct symbol *goto_label;
/* computed gotos have these: */
struct expression *goto_expression;
struct symbol_list *target_list;
};
struct /* asm */ {
struct expression *asm_string;
struct expression_list *asm_outputs;
struct expression_list *asm_inputs;
struct expression_list *asm_clobbers;
struct symbol_list *asm_labels;
};
struct /* range */ {
struct expression *range_expression;
struct expression *range_low;
struct expression *range_high;
};
};
};
struct parse_state_t {
struct symbol_list **function_symbol_list;
struct symbol_list *function_computed_target_list;
struct statement_list *function_computed_goto_list;
struct symbol * int_types[4];
struct symbol * signed_types[5];
struct symbol * unsigned_types[5];
struct symbol * real_types[3];
struct symbol * char_types[3];
struct symbol ** types[7];
};
extern void dmrC_init_parser(struct dmr_C *C, int stream);
void dmrC_destroy_parser(struct dmr_C *C);
extern struct token *dmrC_parse_expression(struct dmr_C *C, struct token *, struct expression **);
extern struct symbol *dmrC_label_symbol(struct dmr_C *C, struct token *token);
extern int dmrC_show_statement(struct dmr_C *C, struct statement *);
extern int dmrC_show_expression(struct dmr_C *C, struct expression *);
typedef void(*validate_decl_t)(struct dmr_C *C, struct symbol *decl);
extern struct token *dmrC_external_declaration(struct dmr_C *C, struct token *token, struct symbol_list **symbol_list, validate_decl_t);
extern struct symbol *dmrC_ctype_integer(struct dmr_C *C, int size, int want_unsigned);
extern void dmrC_copy_statement(struct dmr_C *C, struct statement *src, struct statement *dst);
extern int dmrC_inline_function(struct dmr_C *C, struct expression *expr, struct symbol *sym);
extern void dmrC_uninline(struct dmr_C *C, struct symbol *sym);
static inline void dmrC_add_statement(struct dmr_C *C, struct statement_list **list, struct statement *stmt)
{
ptrlist_add((struct ptr_list **)list, stmt, &C->ptrlist_allocator);
}
static inline void dmrC_add_expression(struct dmr_C *C, struct expression_list **list, struct expression *expr)
{
ptrlist_add((struct ptr_list **)list, expr, &C->ptrlist_allocator);
}
static inline int dmrC_expression_list_size(struct expression_list *list)
{
return ptrlist_size((struct ptr_list *)list);
}
extern int dmrC_test_parse();
#ifdef __cplusplus
}
#endif
#endif /* PARSE_H */

@ -0,0 +1,59 @@
/*
* This version is part of the dmr_c project.
* Copyright (C) 2017 Dibyendu Majumdar
*/
#ifndef DMR_C_PORT_H
#define DMR_C_PORT_H
#ifndef _WIN32
#include <unistd.h>
#include <alloca.h>
#else
#include <io.h>
#include <malloc.h>
#endif
#if defined(_WIN32) && defined(_MSC_VER)
#include <stdlib.h>
#ifndef __cplusplus
#define inline __inline
#endif
#define __alignof__ __alignof
#define __builtin_bswap16 _byteswap_ushort
#define __builtin_bswap32 _byteswap_ulong
#define __builtin_bswap64 _byteswap_uint64
#endif
#ifdef __GNUC__
#define FORMAT_ATTR(pos) __attribute__((__format__(__printf__, pos, pos + 1)))
#define NORETURN_ATTR __attribute__((__noreturn__))
#define SENTINEL_ATTR __attribute__((__sentinel__))
#else
#define FORMAT_ATTR(pos)
#define NORETURN_ATTR
#define SENTINEL_ATTR
#endif
#ifdef __cplusplus
extern "C" {
#endif
void *dmrC_blob_alloc(size_t size);
void dmrC_blob_free(void *addr, size_t size);
long double dmrC_string_to_ld(const char *nptr, char **endptr);
#include <stdint.h>
#ifdef ASMJIT_STATIC
struct backend_data { uint64_t x[2]; };
#define DMRC_BACKEND_TYPE struct backend_data
#else
#define DMRC_BACKEND_TYPE void *
#endif
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

@ -0,0 +1,976 @@
/*
* ptrlist.c
*
* Pointer ptrlist_t manipulation
*
* (C) Copyright Linus Torvalds 2003-2005
*/
/*
* This version is part of the dmr_c project.
* Copyright (C) 2017 Dibyendu Majumdar
*/
#define PARANOIA 1
#include <ptrlist.h>
#include <stdio.h>
#include <stdlib.h>
/* The ptr list */
/* For testing we change this */
static int N_ = LIST_NODE_NR;
void ptrlist_split_node(struct ptr_list *head)
{
int old = head->nr_, nr = old / 2;
struct allocator *alloc = head->allocator_;
assert(alloc);
struct ptr_list *newlist =
(struct ptr_list *)dmrC_allocator_allocate(alloc, 0);
struct ptr_list *next = head->next_;
newlist->allocator_ = alloc;
old -= nr;
head->nr_ = old;
newlist->next_ = next;
next->prev_ = newlist;
newlist->prev_ = head;
head->next_ = newlist;
newlist->nr_ = nr;
memcpy(newlist->list_, head->list_ + old, nr * sizeof(void *));
memset(head->list_ + old, 0xf0, nr * sizeof(void *));
}
struct ptr_list_iter ptrlist_forward_iterator(struct ptr_list *head)
{
struct ptr_list_iter iter;
iter.__head = iter.__list = head;
iter.__nr = -1;
return iter;
}
// Reverse iterator has to start from previous node not previous entry
// in the given head
struct ptr_list_iter ptrlist_reverse_iterator(struct ptr_list *head)
{
struct ptr_list_iter iter;
iter.__head = iter.__list = head ? head->prev_ : NULL;
iter.__nr = iter.__head ? iter.__head->nr_ : 0;
return iter;
}
void *ptrlist_iter_next(struct ptr_list_iter *self)
{
if (self->__head == NULL)
return NULL;
self->__nr++;
Lretry:
if (self->__nr < self->__list->nr_) {
void *ptr = self->__list->list_[self->__nr];
if (self->__list->rm_ && !ptr) {
self->__nr++;
goto Lretry;
}
return ptr;
} else if (self->__list->next_ != self->__head) {
self->__list = self->__list->next_;
self->__nr = 0;
goto Lretry;
}
return NULL;
}
void *ptrlist_nth_entry(struct ptr_list *list, unsigned int idx)
{
struct ptr_list *head = list;
if (!head)
return NULL;
do {
unsigned int nr = list->nr_;
if (idx < nr)
return list->list_[idx];
else
idx -= nr;
} while ((list = list->next_) != head);
return NULL;
}
void *ptrlist_iter_prev(struct ptr_list_iter *self)
{
if (self->__head == NULL)
return NULL;
self->__nr--;
Lretry:
if (self->__nr >= 0 && self->__nr < self->__list->nr_) {
void *ptr = self->__list->list_[self->__nr];
if (self->__list->rm_ && !ptr) {
self->__nr--;
goto Lretry;
}
return ptr;
} else if (self->__list->prev_ != self->__head) {
self->__list = self->__list->prev_;
self->__nr = self->__list->nr_ - 1;
goto Lretry;
}
return NULL;
}
void ptrlist_iter_split_current(struct ptr_list_iter *self)
{
if (self->__list->nr_ == N_) {
/* full so split */
ptrlist_split_node(self->__list);
if (self->__nr >= self->__list->nr_) {
self->__nr -= self->__list->nr_;
self->__list = self->__list->next_;
}
}
}
void ptrlist_iter_insert(struct ptr_list_iter *self, void *newitem)
{
assert(self->__nr >= 0);
ptrlist_iter_split_current(self);
void **__this = self->__list->list_ + self->__nr;
void **__last = self->__list->list_ + self->__list->nr_ - 1;
while (__last >= __this) {
__last[1] = __last[0];
__last--;
}
*__this = newitem;
self->__list->nr_++;
}
void ptrlist_iter_remove(struct ptr_list_iter *self)
{
assert(self->__nr >= 0);
void **__this = self->__list->list_ + self->__nr;
void **__last = self->__list->list_ + self->__list->nr_ - 1;
while (__this < __last) {
__this[0] = __this[1];
__this++;
}
*__this = (void *)((uintptr_t)0xf0f0f0f0);
self->__list->nr_--;
self->__nr--;
}
void ptrlist_iter_set(struct ptr_list_iter *self, void *ptr)
{
assert(self->__list && self->__nr >= 0 &&
self->__nr < self->__list->nr_);
self->__list->list_[self->__nr] = ptr;
}
void ptrlist_iter_mark_deleted(struct ptr_list_iter *self)
{
ptrlist_iter_set(self, NULL);
self->__list->rm_++;
}
int ptrlist_size(const struct ptr_list *head) {
int nr = 0;
if (head) {
const struct ptr_list *list = head;
do {
nr += list->nr_ - list->rm_;
} while ((list = list->next_) != head);
}
return nr;
}
void **ptrlist_add(struct ptr_list **listp, void *ptr, struct allocator *alloc)
{
struct ptr_list *list = *listp;
struct ptr_list *last = NULL;
void **ret;
int nr;
if (!list || (nr = (last = list->prev_)->nr_) >= N_) {
struct ptr_list *newlist =
(struct ptr_list *)dmrC_allocator_allocate(alloc, 0);
newlist->allocator_ = alloc;
if (!list) {
newlist->next_ = newlist;
newlist->prev_ = newlist;
*listp = newlist;
} else {
newlist->prev_ = last;
newlist->next_ = list;
list->prev_ = newlist;
last->next_ = newlist;
}
last = newlist;
nr = 0;
}
ret = last->list_ + nr;
*ret = ptr;
nr++;
last->nr_ = nr;
return ret;
}
void *ptrlist_first(struct ptr_list *list)
{
if (!list)
return NULL;
return list->list_[0];
}
void *ptrlist_last(struct ptr_list *list)
{
if (!list)
return NULL;
list = list->prev_;
return list->list_[list->nr_ - 1];
}
/*
* Linearize the entries of a list up to a total of 'max',
* and return the nr of entries linearized.
*
* The array to linearize into (second argument) should really
* be "void *x[]", but we want to let people fill in any kind
* of pointer array, so let's just call it "void **".
*/
int ptrlist_linearize(struct ptr_list *head, void **arr, int max) {
int nr = 0;
if (head && max > 0) {
struct ptr_list *list = head;
do {
int i = list->nr_;
if (i > max)
i = max;
memcpy(arr, list->list_, i * sizeof(void *));
arr += i;
nr += i;
max -= i;
if (!max)
break;
} while ((list = list->next_) != head);
}
return nr;
}
/*
* When we've walked the list and deleted entries,
* we may need to re-pack it so that we don't have
* any empty blocks left (empty blocks upset the
* walking code
*/
void ptrlist_pack(struct ptr_list **listp)
{
struct ptr_list *head = *listp;
if (head) {
struct ptr_list *entry = head;
do {
struct ptr_list *next;
restart:
next = entry->next_;
if (!entry->nr_) {
struct ptr_list *prev;
if (next == entry) {
dmrC_allocator_free(entry->allocator_, entry);
*listp = NULL;
return;
}
prev = entry->prev_;
prev->next_ = next;
next->prev_ = prev;
dmrC_allocator_free(entry->allocator_, entry);
if (entry == head) {
*listp = next;
head = next;
entry = next;
goto restart;
}
}
entry = next;
} while (entry != head);
}
}
void ptrlist_remove_all(struct ptr_list **listp) {
struct ptr_list *tmp, *list = *listp;
if (!list)
return;
list->prev_->next_ = NULL;
while (list) {
tmp = list;
list = list->next_;
dmrC_allocator_free(tmp->allocator_, tmp);
}
*listp = NULL;
}
int ptrlist_remove(struct ptr_list **self, void *entry, int count) {
struct ptr_list_iter iter = ptrlist_forward_iterator(*self);
for (void *ptr = ptrlist_iter_next(&iter); ptr != NULL;
ptr = ptrlist_iter_next(&iter)) {
if (ptr == entry) {
ptrlist_iter_remove(&iter);
if (!--count)
goto out;
}
}
assert(count <= 0);
out:
ptrlist_pack(self);
return count;
}
int ptrlist_replace(struct ptr_list **self, void *old_ptr, void *new_ptr,
int count) {
struct ptr_list_iter iter = ptrlist_forward_iterator(*self);
for (void *ptr = ptrlist_iter_next(&iter); ptr != NULL;
ptr = ptrlist_iter_next(&iter)) {
if (ptr == old_ptr) {
ptrlist_iter_set(&iter, new_ptr);
if (!--count)
goto out;
}
}
assert(count <= 0);
out:
return count;
}
/* This removes the last entry, but doesn't pack the ptr list */
void *ptrlist_undo_last(struct ptr_list **head)
{
struct ptr_list *last, *first = *head;
if (!first)
return NULL;
last = first;
do {
last = last->prev_;
if (last->nr_) {
void *ptr;
int nr = --last->nr_;
ptr = last->list_[nr];
last->list_[nr] = (void *)((intptr_t)0xf1f1f1f1);
return ptr;
}
} while (last != first);
return NULL;
}
void *ptrlist_delete_last(struct ptr_list **head)
{
void *ptr = NULL;
struct ptr_list *last, *first = *head;
if (!first)
return NULL;
last = first->prev_;
if (last->nr_)
ptr = last->list_[--last->nr_];
if (last->nr_ <= 0) {
first->prev_ = last->prev_;
last->prev_->next_ = first;
if (last == first)
*head = NULL;
dmrC_allocator_free(last->allocator_, last);
}
return ptr;
}
void ptrlist_concat(struct ptr_list *a, struct ptr_list **b) {
struct allocator *alloc = NULL;
struct ptr_list_iter iter = ptrlist_forward_iterator(a);
if (a)
alloc = a->allocator_;
else if (*b)
alloc = (*b)->allocator_;
else
return;
for (void *ptr = ptrlist_iter_next(&iter); ptr != NULL;
ptr = ptrlist_iter_next(&iter)) {
ptrlist_add(b, ptr, alloc);
}
}
/*
* sort_list: a stable sort for lists.
*
* Time complexity: O(n*log n)
* [assuming limited zero-element fragments]
*
* Space complexity: O(1).
*
* Stable: yes.
*/
static void array_sort(void **ptr, int nr, void *userdata,
int (*cmp)(void *, const void *, const void *)) {
int i;
for (i = 1; i < nr; i++) {
void *p = ptr[i];
if (cmp(userdata, ptr[i - 1], p) > 0) {
int j = i;
do {
ptr[j] = ptr[j - 1];
if (!--j)
break;
} while (cmp(userdata, ptr[j - 1], p) > 0);
ptr[j] = p;
}
}
}
static void verify_sorted(struct ptr_list *l, int n, void *userdata,
int (*cmp)(void *, const void *, const void *)) {
int i = 0;
const void *a;
struct ptr_list *head = l;
while (l->nr_ == 0) {
l = l->next_;
if (--n == 0)
return;
assert(l != head);
}
a = l->list_[0];
while (n > 0) {
const void *b;
if (++i >= l->nr_) {
i = 0;
l = l->next_;
n--;
assert(l != head || n == 0);
continue;
}
b = l->list_[i];
assert(cmp(userdata, a, b) <= 0);
a = b;
}
}
static void flush_to(struct ptr_list *b, void **buffer, int *nbuf) {
int nr = b->nr_;
assert(*nbuf >= nr);
memcpy(b->list_, buffer, nr * sizeof(void *));
*nbuf = *nbuf - nr;
memmove(buffer, buffer + nr, *nbuf * sizeof(void *));
}
static void dump_to(struct ptr_list *b, void **buffer, int nbuf) {
assert(nbuf <= b->nr_);
memcpy(b->list_, buffer, nbuf * sizeof(void *));
}
// Merge two already-sorted sequences of blocks:
// (b1_1, ..., b1_n) and (b2_1, ..., b2_m)
// Since we may be moving blocks around, we return the new head
// of the merged list.
static struct ptr_list *
merge_block_seqs(struct ptr_list *b1, int n, struct ptr_list *b2,
int m, void *userdata, int (*cmp)(void *, const void *, const void *)) {
int i1 = 0, i2 = 0;
void *buffer[2 * LIST_NODE_NR];
int nbuf = 0;
struct ptr_list *newhead = b1;
// printf ("Merging %d blocks at %p with %d blocks at %p\n", n, b1, m, b2);
// Skip empty blocks in b2.
while (b2->nr_ == 0) {
// BEEN_THERE('F');
b2 = b2->next_;
if (--m == 0) {
// BEEN_THERE('G');
return newhead;
}
}
// Do a quick skip in case entire blocks from b1 are
// already less than smallest element in b2.
while (b1->nr_ == 0 ||
cmp(userdata, PTR_ENTRY(b1, b1->nr_ - 1), PTR_ENTRY(b2,0)) < 0) {
// printf ("Skipping whole block.\n");
// BEEN_THERE('H');
b1 = b1->next_;
if (--n == 0) {
// BEEN_THERE('I');
return newhead;
}
}
while (1) {
void *d1 = PTR_ENTRY(b1,i1);
void *d2 = PTR_ENTRY(b2,i2);
assert(i1 >= 0 && i1 < b1->nr_);
assert(i2 >= 0 && i2 < b2->nr_);
assert(b1 != b2);
assert(n > 0);
assert(m > 0);
if (cmp(userdata, d1, d2) <= 0) {
// BEEN_THERE('J');
buffer[nbuf++] = d1;
// Element from b1 is smaller
if (++i1 >= b1->nr_) {
// BEEN_THERE('L');
flush_to(b1, buffer, &nbuf);
do {
b1 = b1->next_;
if (--n == 0) {
// BEEN_THERE('O');
while (b1 != b2) {
// BEEN_THERE('P');
flush_to(b1, buffer, &nbuf);
b1 = b1->next_;
}
assert(nbuf == i2);
dump_to(b2, buffer, nbuf);
return newhead;
}
} while (b1->nr_ == 0);
i1 = 0;
}
} else {
// BEEN_THERE('K');
// Element from b2 is smaller
buffer[nbuf++] = d2;
if (++i2 >= b2->nr_) {
struct ptr_list *l = b2;
// BEEN_THERE('M');
// OK, we finished with b2. Pull it out
// and plug it in before b1.
b2 = b2->next_;
b2->prev_ = l->prev_;
b2->prev_->next_ = b2;
l->next_ = b1;
l->prev_ = b1->prev_;
l->next_->prev_ = l;
l->prev_->next_ = l;
if (b1 == newhead) {
// BEEN_THERE('N');
newhead = l;
}
flush_to(l, buffer, &nbuf);
b2 = b2->prev_;
do {
b2 = b2->next_;
if (--m == 0) {
// BEEN_THERE('Q');
assert(nbuf == i1);
dump_to(b1, buffer, nbuf);
return newhead;
}
} while (b2->nr_ == 0);
i2 = 0;
}
}
}
}
void ptrlist_sort(struct ptr_list **plist, void *userdata,
int (*cmp)(void *, const void *, const void *)) {
struct ptr_list *head = *plist, *list = head;
int blocks = 1;
assert(N_ == LIST_NODE_NR);
if (!head)
return;
// Sort all the sub-lists
do {
array_sort(list->list_, list->nr_, userdata, cmp);
#ifdef PARANOIA
verify_sorted(list, 1, userdata, cmp);
#endif
list = list->next_;
} while (list != head);
// Merge the damn things together
while (1) {
struct ptr_list *block1 = head;
do {
struct ptr_list *block2 = block1;
struct ptr_list *next, *newhead;
int i;
for (i = 0; i < blocks; i++) {
block2 = block2->next_;
if (block2 == head) {
if (block1 == head) {
// BEEN_THERE('A');
*plist = head;
return;
}
// BEEN_THERE('B');
goto next_pass;
}
}
next = block2;
for (i = 0; i < blocks;) {
next = next->next_;
i++;
if (next == head) {
// BEEN_THERE('C');
break;
}
// BEEN_THERE('D');
}
newhead = merge_block_seqs(block1, blocks, block2, i, userdata, cmp);
#ifdef PARANOIA
verify_sorted(newhead, blocks + i, userdata, cmp);
#endif
if (block1 == head) {
// BEEN_THERE('E');
head = newhead;
}
block1 = next;
} while (block1 != head);
next_pass:
blocks <<= 1;
}
}
static int int_cmp(void *ud, const void *_a, const void *_b) {
const int *a = (const int *)_a;
const int *b = (const int *)_b;
return *a - *b;
}
#define MIN(_x, _y) ((_x) < (_y) ? (_x) : (_y))
static int test_sort() {
int i, *e;
const int N = 10000;
srand(N);
for (i = 0; i < 1000; i++)
(void)rand();
struct allocator ptrlist_allocator;
dmrC_allocator_init(&ptrlist_allocator, "ptrlist_nodes", sizeof(struct ptr_list),
__alignof__(struct ptr_list), CHUNK);
struct allocator int_allocator;
dmrC_allocator_init(&int_allocator, "ints", sizeof(int), __alignof__(int), CHUNK);
struct ptr_list *int_list = NULL;
for (i = 0; i < N; i++) {
e = (int*)dmrC_allocator_allocate(&int_allocator, 0);
*e = rand();
ptrlist_add(&int_list, e, &ptrlist_allocator);
}
if (ptrlist_size(int_list) != N)
return 1;
ptrlist_sort(&int_list, NULL, int_cmp);
// Sort already sorted stuff.
ptrlist_sort(&int_list, NULL, int_cmp);
int *p = NULL;
struct ptr_list_iter iter = ptrlist_forward_iterator(int_list);
int count = 0;
for (int *k = (int*)ptrlist_iter_next(&iter); k != NULL;
k = (int*)ptrlist_iter_next(&iter)) {
if (p != NULL) {
if (*k < *p)
return 1;
}
p = k;
count++;
}
if (count != N)
return 1;
struct ptr_list *l = int_list, *l2;
l2 = l;
int expected_count = 0;
do {
l2->nr_ = MIN(l2->nr_, rand() % 3);
for (i = 0; i < l2->nr_; i++) {
*((int *)(l2->list_[i])) = rand();
expected_count++;
}
l2 = l2->next_;
} while (l2 != l);
ptrlist_sort(&int_list, NULL, int_cmp);
p = NULL;
iter = ptrlist_forward_iterator(int_list);
count = 0;
for (int *k = (int*)ptrlist_iter_next(&iter); k != NULL;
k = (int*)ptrlist_iter_next(&iter)) {
if (p != NULL) {
if (*k < *p)
return 1;
}
p = k;
count++;
}
if (count != expected_count)
return 1;
ptrlist_remove_all(&int_list);
dmrC_allocator_destroy(&int_allocator);
dmrC_allocator_destroy(&ptrlist_allocator);
return 0;
}
struct mystruct {
int i;
};
struct mytoken {
const char *a;
};
static int test_ptrlist_basics() {
struct allocator ptrlist_allocator;
dmrC_allocator_init(&ptrlist_allocator, "ptrlist_nodes", sizeof(struct ptr_list),
__alignof__(struct ptr_list), CHUNK);
struct allocator token_allocator;
dmrC_allocator_init(&token_allocator, "ptr_list_tokens", sizeof(struct mytoken),
__alignof__(struct mytoken), CHUNK);
struct ptr_list *token_list = NULL;
if (ptrlist_size(token_list) != 0)
return 1;
struct mytoken *tok1 = (struct mytoken *)dmrC_allocator_allocate(&token_allocator, 0);
struct mytoken **tok1p = (struct mytoken **)ptrlist_add(&token_list, tok1, &ptrlist_allocator);
if (ptrlist_size(token_list) != 1)
return 1;
if (tok1 != *tok1p)
return 1;
if (ptrlist_first(token_list) != tok1)
return 1;
if (ptrlist_last(token_list) != tok1)
return 1;
struct mytoken *tok2 = (struct mytoken *)dmrC_allocator_allocate(&token_allocator, 0);
struct mytoken **tok2p = (struct mytoken **)ptrlist_add(&token_list, tok2, &ptrlist_allocator);
if (ptrlist_size(token_list) != 2)
return 1;
struct mytoken *tok3 = (struct mytoken *)dmrC_allocator_allocate(&token_allocator, 0);
ptrlist_add(&token_list, tok3, &ptrlist_allocator);
if (ptrlist_size(token_list) != 3)
return 1;
struct mytoken *tok4 = (struct mytoken *)dmrC_allocator_allocate(&token_allocator, 0);
ptrlist_add(&token_list, tok4, &ptrlist_allocator);
if (ptrlist_size(token_list) != 4)
return 1;
struct mytoken *tok5 = (struct mytoken *)dmrC_allocator_allocate(&token_allocator, 0);
struct mytoken **tok5p = (struct mytoken **)ptrlist_add(&token_list, tok5, &ptrlist_allocator);
if (ptrlist_size(token_list) != 5)
return 1;
if (tok2 != *tok2p)
return 1;
if (tok5 != *tok5p)
return 1;
if (ptrlist_first(token_list) != tok1)
return 1;
if (ptrlist_last(token_list) != tok5)
return 1;
struct mytoken *toks[5];
int lin1 = ptrlist_linearize(token_list, (void **)toks, 5);
if (lin1 != 5)
return 1;
if (toks[0] != tok1)
return 1;
if (toks[1] != tok2)
return 1;
if (toks[2] != tok3)
return 1;
if (toks[3] != tok4)
return 1;
if (toks[4] != tok5)
return 1;
if (ptrlist_size(token_list) != 5)
return 1;
ptrlist_pack(&token_list);
if (ptrlist_size(token_list) != 5)
return 1;
if (ptrlist_first(token_list) != tok1)
return 1;
if (ptrlist_last(token_list) != tok5)
return 1;
const int X = 5 + 1;
const int Y = X - 1;
const int Z = Y - 1;
struct ptr_list_iter iter1 = ptrlist_forward_iterator(token_list);
for (int i = 0; i < X; i++) {
struct mytoken *tk = (struct mytoken *)ptrlist_iter_next(&iter1);
if (tk == NULL) {
if (i == Y)
break;
return 1;
}
if (tk != toks[i])
return 1;
}
struct ptr_list_iter iter2 = ptrlist_reverse_iterator(token_list);
for (int i = 0; i < X; i++) {
struct mytoken *tk = (struct mytoken *)ptrlist_iter_prev(&iter2);
if (tk == NULL) {
if (i == Y)
break;
return 1;
}
if (tk != toks[Z - i])
return 1;
}
struct mytoken *tok0 = (struct mytoken *)dmrC_allocator_allocate(&token_allocator, 0);
struct ptr_list_iter iter3 = ptrlist_forward_iterator(token_list);
if (!ptrlist_iter_next(&iter3))
return 1;
ptrlist_iter_insert(&iter3, tok0);
if (ptrlist_size(token_list) != 6)
return 1;
if (ptrlist_first(token_list) != tok0)
return 1;
if (ptrlist_last(token_list) != tok5)
return 1;
struct allocator mystruct_allocator;
dmrC_allocator_init(&mystruct_allocator, "mystructs", sizeof(struct mystruct),
__alignof__(struct mystruct), CHUNK);
struct ptr_list *mystruct_list = NULL;
struct mystruct *s1 = (struct mystruct *)dmrC_allocator_allocate(&mystruct_allocator, 0);
s1->i = 1;
struct mystruct *s2 = (struct mystruct *)dmrC_allocator_allocate(&mystruct_allocator, 0);
s2->i = 2;
struct mystruct *s3 = (struct mystruct *)dmrC_allocator_allocate(&mystruct_allocator, 0);
s3->i = 3;
struct mystruct *s4 = (struct mystruct *)dmrC_allocator_allocate(&mystruct_allocator, 0);
s4->i = 4;
struct mystruct *s5 = (struct mystruct *)dmrC_allocator_allocate(&mystruct_allocator, 0);
s5->i = 5;
struct mystruct *s6 = (struct mystruct *)dmrC_allocator_allocate(&mystruct_allocator, 0);
s6->i = 6;
ptrlist_add(&mystruct_list, s1, &ptrlist_allocator);
ptrlist_add(&mystruct_list, s2, &ptrlist_allocator);
ptrlist_add(&mystruct_list, s3, &ptrlist_allocator);
ptrlist_add(&mystruct_list, s4, &ptrlist_allocator);
ptrlist_add(&mystruct_list, s5, &ptrlist_allocator);
ptrlist_add(&mystruct_list, s6, &ptrlist_allocator);
struct mystruct *serial1_expected[6] = { s1, s2, s3, s4, s5, s6 };
struct mystruct *serial1_got[6];
ptrlist_linearize(mystruct_list, (void **)serial1_got, 6);
for (int i = 0; i < 6; i++) {
if (serial1_expected[i] != serial1_got[i])
return 1;
}
if (ptrlist_remove(&mystruct_list, s3, 1) != 0)
return 1;
struct ptr_list_iter iter4 = ptrlist_forward_iterator(mystruct_list);
for (struct mystruct *p = (struct mystruct *)ptrlist_iter_next(&iter4); p != NULL;
p = (struct mystruct *)ptrlist_iter_next(&iter4)) {
if (p->i == 4)
ptrlist_iter_remove(&iter4);
}
if (ptrlist_size(mystruct_list) != 4)
return 1;
struct mystruct *serial3_expected[4] = { s1, s2, s5, s6 };
struct mystruct *serial3_got[4];
int reverse_expected[2] = { 2, 1 };
int i = 0;
struct mystruct *p;
FOR_EACH_PTR(mystruct_list, p) {
if (i == 4)
return 1;
serial3_got[i++] = p;
if (i == 3) {
struct mystruct *p2;
int j = 0;
RECURSE_PTR_REVERSE(p, p2) {
if (j >= 2 || reverse_expected[j] != p2->i)
return 1;
j++;
} END_FOR_EACH_PTR_REVERSE(p2);
}
} END_FOR_EACH_PTR(p);
if (i != 4)
return 1;
for (int i = 0; i < 4; i++) {
if (serial3_expected[i] != serial3_got[i])
return 1;
}
i = 0;
PREPARE_PTR_LIST(mystruct_list, p);
while (p != NULL) {
if (i == 4)
return 1;
serial3_got[i++] = p;
NEXT_PTR_LIST(p);
}
FINISH_PTR_LIST(p);
if (i != 4)
return 1;
for (int i = 0; i < 4; i++) {
if (serial3_expected[i] != serial3_got[i])
return 1;
}
i = 0;
FOR_EACH_PTR_REVERSE(mystruct_list, p) {
if (i == 4)
return 1;
serial3_got[i++] = p;
if (i == 2) {
struct mystruct *p3;
int j = 0;
RECURSE_PTR_REVERSE(p, p3) {
if (j >= 2 || reverse_expected[j] != p3->i)
return 1;
j++;
} END_FOR_EACH_PTR_REVERSE(p3);
}
} END_FOR_EACH_PTR_REVERSE(p);
if (i != 4)
return 1;
for (int i = 0; i < 4; i++) {
if (serial3_expected[3-i] != serial3_got[i])
return 1;
}
ptrlist_remove_all(&token_list);
ptrlist_remove_all(&mystruct_list);
dmrC_allocator_destroy(&token_allocator);
dmrC_allocator_destroy(&mystruct_allocator);
dmrC_allocator_destroy(&ptrlist_allocator);
return 0;
}
int test_ptrlist() {
if (test_sort() != 0)
return 1;
/* For testing we set N_ temporarily */
N_ = 2;
int failure_count = test_ptrlist_basics();
N_ = LIST_NODE_NR;
if (failure_count == 0)
printf("ptrlist test okay\n");
return failure_count;
}

@ -0,0 +1,339 @@
#ifndef DMR_C_PTRLIST_H
#define DMR_C_PTRLIST_H
/*
* Generic pointer list manipulation code.
*
* (C) Copyright Linus Torvalds 2003-2005
*/
/*
* This version is part of the dmr_c project.
* Copyright (C) 2017 Dibyendu Majumdar
*/
#include <allocate.h>
#include <assert.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* The ptr list data structure is like a train - with cars linked to each other.
* Just as in a train each car has many seats, so in ptr list each "node" has
* several entries. Unlike a train however, the ptr list is arranged as a ring,
* i.e. the the front and back nodes are linked to each other. Hence there is no
* such thing as a 'head' of the list - i.e. any node can be the head!
*/
#ifndef LIST_NODE_NR
#define LIST_NODE_NR (29)
#endif
#define DECLARE_PTR_LIST(listname, type) \
struct listname { \
int nr_ : 8; \
int rm_ : 8; \
struct listname *prev_; \
struct listname *next_; \
struct allocator *allocator_; \
type *list_[LIST_NODE_NR]; \
}
/* Each node in the list */
DECLARE_PTR_LIST(ptr_list, void);
struct ptr_list_iter {
struct ptr_list *__head;
struct ptr_list *__list;
int __nr;
};
/* The ptr list */
extern int ptrlist_size(const struct ptr_list *self);
extern void **ptrlist_add(struct ptr_list **self, void *ptr, struct allocator *alloc);
extern void *ptrlist_nth_entry(struct ptr_list *list, unsigned int idx);
extern void *ptrlist_first(struct ptr_list *list);
extern void *ptrlist_last(struct ptr_list *list);
extern int ptrlist_linearize(struct ptr_list *head, void **arr, int max);
extern void ptrlist_split_node(struct ptr_list *head);
extern void ptrlist_pack(struct ptr_list **self);
extern void ptrlist_remove_all(struct ptr_list **self);
extern int ptrlist_remove(struct ptr_list **self, void *entry, int count);
extern int ptrlist_replace(struct ptr_list **self, void *old_ptr, void *new_ptr,
int count);
extern void *ptrlist_undo_last(struct ptr_list **self);
extern void *ptrlist_delete_last(struct ptr_list **self);
extern void ptrlist_concat(struct ptr_list *a, struct ptr_list **self);
extern void ptrlist_sort(struct ptr_list **self, void *,
int (*cmp)(void *, const void *, const void *));
/* iterator functions */
extern struct ptr_list_iter ptrlist_forward_iterator(struct ptr_list *self);
extern struct ptr_list_iter ptrlist_reverse_iterator(struct ptr_list *self);
extern void *ptrlist_iter_next(struct ptr_list_iter *self);
extern void *ptrlist_iter_prev(struct ptr_list_iter *self);
extern void ptrlist_iter_split_current(struct ptr_list_iter *self);
extern void ptrlist_iter_insert(struct ptr_list_iter *self, void *newitem);
extern void ptrlist_iter_remove(struct ptr_list_iter *self);
extern void ptrlist_iter_set(struct ptr_list_iter *self, void *ptr);
extern void ptrlist_iter_mark_deleted(struct ptr_list_iter *self);
static inline void **ptrlist_iter_this_address(struct ptr_list_iter *self) {
return &self->__list->list_[self->__nr];
}
#define ptr_list_empty(x) ((x) == NULL)
#define PTR_ENTRY_NOTAG(h,i) ((h)->list_[i])
#define PTR_ENTRY(h,i) (void *)(PTR_ENTRY_NOTAG(h,i))
#if 1
#define FOR_EACH_PTR(list, var) \
{ struct ptr_list_iter var##iter__ = ptrlist_forward_iterator((struct ptr_list *)list); \
for (var = ptrlist_iter_next(&var##iter__); var != NULL; var = ptrlist_iter_next(&var##iter__))
//#define FOR_EACH_PTR_TYPED(list, type, var) \
// { struct ptr_list_iter var##iter__ = ptrlist_forward_iterator(list); \
// for (var = (type) ptrlist_iter_next(&var##iter__); var != NULL; var = (type) ptrlist_iter_next(&var##iter__))
//#define FOR_EACH_PTR_TYPE(list, var, ptr_type) \
// { struct ptr_list_iter var##iter__ = ptrlist_forward_iterator(list); \
// for (var = (ptr_type) ptrlist_iter_next(&var##iter__); var != NULL; var = (ptr_type) ptrlist_iter_next(&var##iter__))
#define END_FOR_EACH_PTR(var) }
#define FOR_EACH_PTR_REVERSE(list, var) \
{ struct ptr_list_iter var##iter__ = ptrlist_reverse_iterator((struct ptr_list *)list); \
for (var = ptrlist_iter_prev(&var##iter__); var != NULL; var = ptrlist_iter_prev(&var##iter__))
#define END_FOR_EACH_PTR_REVERSE(var) }
#define RECURSE_PTR_REVERSE(list, var) \
{ struct ptr_list_iter var##iter__ = list##iter__; \
for (var = ptrlist_iter_prev(&var##iter__); var != NULL; var = ptrlist_iter_prev(&var##iter__))
#define PREPARE_PTR_LIST(list, var) \
struct ptr_list_iter var##iter__ = ptrlist_forward_iterator((struct ptr_list *)list); \
var = ptrlist_iter_next(&var##iter__)
#define NEXT_PTR_LIST(var) \
var = ptrlist_iter_next(&var##iter__)
#define FINISH_PTR_LIST(var)
#define THIS_ADDRESS(type, var) \
(type *)ptrlist_iter_this_address(&var##iter__)
#define DELETE_CURRENT_PTR(var) \
ptrlist_iter_remove(&var##iter__)
#define REPLACE_CURRENT_PTR(type, var, replacement) \
ptrlist_iter_set(&var##iter__, replacement)
#define INSERT_CURRENT(newval, var) \
ptrlist_iter_insert(&var##iter__, newval)
#define MARK_CURRENT_DELETED(PTR_TYPE, var) \
ptrlist_iter_mark_deleted(&var##iter__)
#else
#define DO_PREPARE(head, ptr, __head, __list, __nr, PTR_ENTRY) \
do { \
struct ptr_list *__head = (struct ptr_list *) (head); \
struct ptr_list *__list = __head; \
int __nr = 0; \
if (__head) ptr = PTR_ENTRY(__head, 0); \
else ptr = NULL
#define DO_NEXT(ptr, __head, __list, __nr, PTR_ENTRY) \
if (ptr) { \
if (++__nr < __list->nr_) { \
ptr = PTR_ENTRY(__list,__nr); \
} else { \
__list = __list->next_; \
ptr = NULL; \
while (__list->nr_ == 0 && __list != __head) \
__list = __list->next_; \
if (__list != __head) { \
__nr = 0; \
ptr = PTR_ENTRY(__list,0); \
} \
} \
}
#define DO_RESET(ptr, __head, __list, __nr, PTR_ENTRY) \
do { \
__nr = 0; \
__list = __head; \
if (__head) ptr = PTR_ENTRY(__head, 0); \
} while (0)
#define DO_FINISH(ptr, __head, __list, __nr) \
(void)(__nr); /* Sanity-check nesting */ \
} while (0)
#define PREPARE_PTR_LIST(head, ptr) \
DO_PREPARE(head, ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY)
#define NEXT_PTR_LIST(ptr) \
DO_NEXT(ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY)
#define RESET_PTR_LIST(ptr) \
DO_RESET(ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY)
#define FINISH_PTR_LIST(ptr) \
DO_FINISH(ptr, __head##ptr, __list##ptr, __nr##ptr)
#define DO_FOR_EACH(head, ptr, __head, __list, __nr, PTR_ENTRY) do { \
struct ptr_list *__head = (struct ptr_list *) (head); \
struct ptr_list *__list = __head; \
if (__head) { \
do { int __nr; \
for (__nr = 0; __nr < __list->nr_; __nr++) { \
do { \
ptr = PTR_ENTRY(__list,__nr); \
if (__list->rm_ && !ptr) \
continue; \
do {
#define DO_END_FOR_EACH(ptr, __head, __list, __nr) \
} while (0); \
} while (0); \
} \
} while ((__list = __list->next_) != __head); \
} \
} while (0)
#define DO_FOR_EACH_REVERSE(head, ptr, __head, __list, __nr, PTR_ENTRY) do { \
struct ptr_list *__head = (struct ptr_list *) (head); \
struct ptr_list *__list = __head; \
if (__head) { \
do { int __nr; \
__list = __list->prev_; \
__nr = __list->nr_; \
while (--__nr >= 0) { \
do { \
ptr = PTR_ENTRY(__list,__nr); \
if (__list->rm_ && !ptr) \
continue; \
do {
#define DO_END_FOR_EACH_REVERSE(ptr, __head, __list, __nr) \
} while (0); \
} while (0); \
} \
} while (__list != __head); \
} \
} while (0)
#define DO_REVERSE(ptr, __head, __list, __nr, new, __newhead, \
__newlist, __newnr, PTR_ENTRY) do { \
struct ptr_list *__newhead = __head; \
struct ptr_list *__newlist = __list; \
int __newnr = __nr; \
new = ptr; \
goto __inside##new; \
if (1) { \
do { \
__newlist = __newlist->prev_; \
__newnr = __newlist->nr_; \
__inside##new: \
while (--__newnr >= 0) { \
do { \
new = PTR_ENTRY(__newlist,__newnr); \
do {
#define RECURSE_PTR_REVERSE(ptr, new) \
DO_REVERSE(ptr, __head##ptr, __list##ptr, __nr##ptr, \
new, __head##new, __list##new, __nr##new, PTR_ENTRY)
#define DO_THIS_ADDRESS(PTR_TYPE, ptr, __head, __list, __nr) \
((PTR_TYPE*) (__list->list_ + __nr))
#define FOR_EACH_PTR(head, ptr) \
DO_FOR_EACH(head, ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY)
#define END_FOR_EACH_PTR(ptr) \
DO_END_FOR_EACH(ptr, __head##ptr, __list##ptr, __nr##ptr)
#define FOR_EACH_PTR_NOTAG(head, ptr) \
DO_FOR_EACH(head, ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY_NOTAG)
#define END_FOR_EACH_PTR_NOTAG(ptr) END_FOR_EACH_PTR(ptr)
#define FOR_EACH_PTR_REVERSE(head, ptr) \
DO_FOR_EACH_REVERSE(head, ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY)
#define END_FOR_EACH_PTR_REVERSE(ptr) \
DO_END_FOR_EACH_REVERSE(ptr, __head##ptr, __list##ptr, __nr##ptr)
#define FOR_EACH_PTR_REVERSE_NOTAG(head, ptr) \
DO_FOR_EACH_REVERSE(head, ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY_NOTAG)
#define END_FOR_EACH_PTR_REVERSE_NOTAG(ptr) END_FOR_EACH_PTR_REVERSE(ptr)
#define THIS_ADDRESS(PTR_TYPE, ptr) \
DO_THIS_ADDRESS(PTR_TYPE, ptr, __head##ptr, __list##ptr, __nr##ptr)
#define DO_SPLIT(ptr, __head, __list, __nr) do { \
ptrlist_split_node(__list); \
if (__nr >= __list->nr_) { \
__nr -= __list->nr_; \
__list = __list->next_; \
}; \
} while (0)
#define DO_INSERT_CURRENT(new, ptr, __head, __list, __nr) do { \
void **__this, **__last; \
if (__list->nr_ == LIST_NODE_NR) \
DO_SPLIT(ptr, __head, __list, __nr); \
__this = __list->list_ + __nr; \
__last = __list->list_ + __list->nr_ - 1; \
while (__last >= __this) { \
__last[1] = __last[0]; \
__last--; \
} \
*__this = (new); \
__list->nr_++; \
} while (0)
#define INSERT_CURRENT(new, ptr) \
DO_INSERT_CURRENT(new, ptr, __head##ptr, __list##ptr, __nr##ptr)
#define DO_DELETE_CURRENT(ptr, __head, __list, __nr) do { \
void **__this = __list->list_ + __nr; \
void **__last = __list->list_ + __list->nr_ - 1; \
while (__this < __last) { \
__this[0] = __this[1]; \
__this++; \
} \
*__this = (void *)((uintptr_t)0xf0f0f0f0); \
__list->nr_--; __nr--; \
} while (0)
#define DELETE_CURRENT_PTR(ptr) \
DO_DELETE_CURRENT(ptr, __head##ptr, __list##ptr, __nr##ptr)
#define REPLACE_CURRENT_PTR(PTR_TYPE, ptr, new_ptr) \
do { *THIS_ADDRESS(PTR_TYPE, ptr) = (new_ptr); } while (0)
#define DO_MARK_CURRENT_DELETED(PTR_TYPE, ptr, __list) do { \
REPLACE_CURRENT_PTR(PTR_TYPE, ptr, NULL); \
__list->rm++; \
} while (0)
#define MARK_CURRENT_DELETED(PTR_TYPE, ptr) \
DO_MARK_CURRENT_DELETED(PTR_TYPE, ptr, __list##ptr)
#endif
extern int test_ptrlist();
#ifdef __cplusplus
}
#endif
#endif

@ -0,0 +1,20 @@
#include <allocate.h>
#include <ptrlist.h>
#include <token.h>
#include <parse.h>
#include <stdio.h>
int main()
{
int failure_count = 0;
failure_count += dmrC_test_allocator();
failure_count += test_ptrlist();
//failure_count += test_tokenizer();
//failure_count += dmrC_test_parse();
if (failure_count == 0)
printf("Tests OK\n");
else
printf("Tests FAILED\n");
return failure_count == 0 ? 0 : 1;
}

@ -0,0 +1,160 @@
/*
* Symbol scoping.
*
* This is pretty trivial.
*
* Copyright (C) 2003 Transmeta Corp.
* 2003-2004 Linus Torvalds
*
* 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.
*/
/*
* This version is part of the dmr_c project.
* Copyright (C) 2017 Dibyendu Majumdar
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <port.h>
#include <lib.h>
#include <allocate.h>
#include <symbol.h>
#include <scope.h>
void dmrC_init_scope(struct dmr_C *C) {
struct scope *scope = (struct scope *)dmrC_allocator_allocate(&C->scope_allocator, 0);
memset(scope, 0, sizeof(*scope));
scope->next = scope;
C->builtin_scope = scope;
C->block_scope = C->builtin_scope; // regular automatic variables etc
C->function_scope = C->builtin_scope; // labels, arguments etc
C->file_scope = C->builtin_scope; // static
C->global_scope = C->builtin_scope; // externally visible
}
void dmrC_destroy_all_scopes(struct dmr_C *C) {
}
void dmrC_bind_scope(struct dmr_C *C, struct symbol *sym, struct scope *scope)
{
sym->scope = scope;
dmrC_add_symbol(C, &scope->symbols, sym);
}
void dmrC_rebind_scope(struct dmr_C *C, struct symbol *sym, struct scope *news)
{
struct scope *old = sym->scope;
if (old == news)
return;
if (old)
ptrlist_remove((struct ptr_list **) &old->symbols, sym, 1);
dmrC_bind_scope(C, sym, news);
}
static void start_scope(struct dmr_C *C, struct scope **s)
{
struct scope *scope = (struct scope *)dmrC_allocator_allocate(&C->scope_allocator, 0);
memset(scope, 0, sizeof(*scope));
scope->next = *s;
*s = scope;
}
void dmrC_start_file_scope(struct dmr_C *C)
{
struct scope *scope = (struct scope *)dmrC_allocator_allocate(&C->scope_allocator, 0);
memset(scope, 0, sizeof(*scope));
scope->next = C->builtin_scope;
C->file_scope = scope;
/* top-level stuff defaults to file scope, "extern" etc will choose global scope */
C->function_scope = scope;
C->block_scope = scope;
}
void dmrC_start_symbol_scope(struct dmr_C *C)
{
start_scope(C, &C->block_scope);
}
void dmrC_start_function_scope(struct dmr_C *C)
{
start_scope(C, &C->function_scope);
start_scope(C, &C->block_scope);
}
static void remove_symbol_scope(struct dmr_C *C, struct symbol *sym)
{
struct symbol **ptr = &sym->ident->symbols;
while (*ptr != sym)
ptr = &(*ptr)->next_id;
*ptr = sym->next_id;
}
static void end_scope(struct dmr_C *C, struct scope **s)
{
struct scope *scope = *s;
struct symbol_list *symbols = scope->symbols;
struct symbol *sym;
*s = scope->next;
scope->symbols = NULL;
FOR_EACH_PTR(symbols, sym) {
remove_symbol_scope(C, sym);
} END_FOR_EACH_PTR(sym);
}
void dmrC_end_file_scope(struct dmr_C *C)
{
end_scope(C, &C->file_scope);
}
void dmrC_new_file_scope(struct dmr_C *C)
{
if (C->file_scope != C->builtin_scope)
dmrC_end_file_scope(C);
dmrC_start_file_scope(C);
}
void dmrC_end_symbol_scope(struct dmr_C *C)
{
end_scope(C, &C->block_scope);
}
void dmrC_end_function_scope(struct dmr_C *C)
{
end_scope(C, &C->block_scope);
end_scope(C, &C->function_scope);
}
int dmrC_is_outer_scope(struct dmr_C *C, struct scope *scope)
{
if (scope == C->block_scope)
return 0;
if (scope == C->builtin_scope && C->block_scope->next == C->builtin_scope)
return 0;
return 1;
}

@ -0,0 +1,73 @@
#ifndef DMR_C_SCOPE_H
#define DMR_C_SCOPE_H
/*
* Symbol scoping is pretty simple.
*
* Copyright (C) 2003 Transmeta Corp.
* 2003 Linus Torvalds
*
* 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.
*/
/*
* This version is part of the dmr_c project.
* Copyright (C) 2017 Dibyendu Majumdar
*/
#include <lib.h>
#ifdef __cplusplus
extern "C" {
#endif
struct scope {
struct token *token; /* Scope start information */
struct symbol_list *symbols; /* List of symbols in this scope */
struct scope *next;
};
static inline int dmrC_toplevel(struct dmr_C *C, struct scope *scope)
{
return scope == C->file_scope || scope == C->global_scope;
}
extern void dmrC_start_file_scope(struct dmr_C *C);
extern void dmrC_end_file_scope(struct dmr_C *C);
extern void dmrC_new_file_scope(struct dmr_C *C);
extern void dmrC_start_symbol_scope(struct dmr_C *C);
extern void dmrC_end_symbol_scope(struct dmr_C *C);
extern void dmrC_start_function_scope(struct dmr_C *C);
extern void dmrC_end_function_scope(struct dmr_C *C);
extern void dmrC_bind_scope(struct dmr_C *C, struct symbol *, struct scope *);
extern void dmrC_rebind_scope(struct dmr_C *C, struct symbol *sym, struct scope *news);
extern int dmrC_is_outer_scope(struct dmr_C *C, struct scope *);
extern void dmrC_init_scope(struct dmr_C *C);
extern void dmrC_destroy_all_scopes(struct dmr_C *C);
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,827 @@
/*
* Symbol lookup and handling.
*
* Copyright (C) 2003 Transmeta Corp.
* 2003-2004 Linus Torvalds
*
* 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.
*/
/*
* This version is part of the dmr_c project.
* Copyright (C) 2017 Dibyendu Majumdar
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <port.h>
#include <lib.h>
#include <allocate.h>
#include <ptrlist.h>
#include <token.h>
#include <parse.h>
#include <symbol.h>
#include <scope.h>
#include <expression.h>
#include <target.h>
/*
* If the symbol is an inline symbol, add it to the list of symbols to parse
*/
void dmrC_access_symbol(struct global_symbols_t *S, struct symbol *sym)
{
if (sym->ctype.modifiers & MOD_INLINE) {
if (!(sym->ctype.modifiers & MOD_ACCESSED)) {
dmrC_add_symbol(S->C, &S->translation_unit_used_list, sym);
sym->ctype.modifiers |= MOD_ACCESSED;
}
}
}
struct symbol *dmrC_lookup_symbol(struct ident *ident, enum namespace_type ns)
{
struct symbol *sym;
for (sym = ident->symbols; sym; sym = sym->next_id) {
if (sym->ns & ns) {
sym->used = 1;
return sym;
}
}
return NULL;
}
struct context *dmrC_alloc_context(struct global_symbols_t *S)
{
return (struct context *)dmrC_allocator_allocate(&S->context_allocator, 0);
}
struct symbol *dmrC_alloc_symbol(struct global_symbols_t *S, struct position pos, int type)
{
struct symbol *sym = (struct symbol *) dmrC_allocator_allocate(&S->symbol_allocator, 0);
sym->type = type;
sym->pos = pos;
sym->endpos.type = 0;
return sym;
}
struct struct_union_info {
unsigned long max_align;
unsigned long bit_size;
int align_size;
};
/*
* Unions are fairly easy to lay out ;)
*/
static void lay_out_union(struct global_symbols_t *S, struct symbol *sym, struct struct_union_info *info)
{
dmrC_examine_symbol_type(S, sym);
// Unnamed bitfields do not affect alignment.
if (sym->ident || !dmrC_is_bitfield_type(sym)) {
if (sym->ctype.alignment > info->max_align)
info->max_align = sym->ctype.alignment;
}
if (sym->bit_size > info->bit_size)
info->bit_size = sym->bit_size;
sym->offset = 0;
}
static int bitfield_base_size(struct symbol *sym)
{
if (sym->type == SYM_NODE)
sym = sym->ctype.base_type;
if (sym->type == SYM_BITFIELD)
sym = sym->ctype.base_type;
return sym->bit_size;
}
/*
* Structures are a bit more interesting to lay out
*/
static void lay_out_struct(struct global_symbols_t *S, struct symbol *sym, struct struct_union_info *info)
{
unsigned long bit_size, align_bit_mask;
int base_size;
dmrC_examine_symbol_type(S, sym);
// Unnamed bitfields do not affect alignment.
if (sym->ident || !dmrC_is_bitfield_type(sym)) {
if (sym->ctype.alignment > info->max_align)
info->max_align = sym->ctype.alignment;
}
bit_size = info->bit_size;
base_size = sym->bit_size;
/*
* Unsized arrays cause us to not align the resulting
* structure size
*/
if (base_size < 0) {
info->align_size = 0;
base_size = 0;
}
align_bit_mask = dmrC_bytes_to_bits(S->C->target, sym->ctype.alignment) - 1;
/*
* Bitfields have some very special rules..
*/
if (dmrC_is_bitfield_type (sym)) {
unsigned long bit_offset = bit_size & align_bit_mask;
int room = bitfield_base_size(sym) - bit_offset;
// Zero-width fields just fill up the unit.
int width = base_size ? base_size : (bit_offset ? room : 0);
if (width > room) {
bit_size = (bit_size + align_bit_mask) & ~align_bit_mask;
bit_offset = 0;
}
sym->offset = dmrC_bits_to_bytes(S->C->target, bit_size - bit_offset);
sym->bit_offset = bit_offset;
sym->ctype.base_type->bit_offset = bit_offset;
info->bit_size = bit_size + width;
// dmrC_warning (sym->pos, "bitfield: offset=%d:%d size=:%d", sym->offset, sym->bit_offset, width);
return;
}
/*
* Otherwise, just align it right and add it up..
*/
bit_size = (bit_size + align_bit_mask) & ~align_bit_mask;
sym->offset = dmrC_bits_to_bytes(S->C->target, bit_size);
info->bit_size = bit_size + base_size;
// dmrC_warning (sym->pos, "regular: offset=%d", sym->offset);
}
static struct symbol * examine_struct_union_type(struct global_symbols_t *S, struct symbol *sym, int advance)
{
struct struct_union_info info = {
.max_align = 1,
.bit_size = 0,
.align_size = 1
};
unsigned long bit_size, bit_align;
void (*fn)(struct global_symbols_t *S, struct symbol *, struct struct_union_info *);
struct symbol *member;
fn = advance ? lay_out_struct : lay_out_union;
FOR_EACH_PTR(sym->symbol_list, member) {
fn(S, member, &info);
} END_FOR_EACH_PTR(member);
if (!sym->ctype.alignment)
sym->ctype.alignment = info.max_align;
bit_size = info.bit_size;
if (info.align_size) {
bit_align = dmrC_bytes_to_bits(S->C->target, sym->ctype.alignment)-1;
bit_size = (bit_size + bit_align) & ~bit_align;
}
sym->bit_size = bit_size;
return sym;
}
static struct symbol *examine_base_type(struct global_symbols_t *S, struct symbol *sym)
{
struct symbol *base_type;
/* Check the base type */
base_type = dmrC_examine_symbol_type(S, sym->ctype.base_type);
if (!base_type || base_type->type == SYM_PTR)
return base_type;
sym->ctype.as |= base_type->ctype.as;
sym->ctype.modifiers |= base_type->ctype.modifiers & MOD_PTRINHERIT;
dmrC_concat_context_list(base_type->ctype.contexts,
&sym->ctype.contexts);
if (base_type->type == SYM_NODE) {
base_type = base_type->ctype.base_type;
sym->ctype.base_type = base_type;
}
return base_type;
}
static struct symbol * examine_array_type(struct global_symbols_t *S, struct symbol *sym)
{
struct symbol *base_type = examine_base_type(S, sym);
unsigned long bit_size = -1, alignment;
struct expression *array_size = sym->array_size;
if (!base_type)
return sym;
if (array_size) {
bit_size = dmrC_array_element_offset(S->C->target, base_type->bit_size,
dmrC_get_expression_value_silent(S->C, array_size));
if (array_size->type != EXPR_VALUE) {
if (S->C->Wvla)
dmrC_warning(S->C, array_size->pos, "Variable length array is used.");
bit_size = -1;
}
}
alignment = base_type->ctype.alignment;
if (!sym->ctype.alignment)
sym->ctype.alignment = alignment;
sym->bit_size = bit_size;
return sym;
}
static struct symbol *examine_bitfield_type(struct global_symbols_t *S, struct symbol *sym)
{
struct symbol *base_type = examine_base_type(S, sym);
unsigned long bit_size, alignment, modifiers;
if (!base_type)
return sym;
bit_size = base_type->bit_size;
if (sym->bit_size > bit_size)
dmrC_warning(S->C, sym->pos, "impossible field-width, %d, for this type", sym->bit_size);
alignment = base_type->ctype.alignment;
if (!sym->ctype.alignment)
sym->ctype.alignment = alignment;
modifiers = base_type->ctype.modifiers;
/* Bitfields are unsigned, unless the base type was explicitly signed */
if (!(modifiers & MOD_EXPLICITLY_SIGNED))
modifiers = (modifiers & ~MOD_SIGNED) | MOD_UNSIGNED;
sym->ctype.modifiers |= modifiers & MOD_SIGNEDNESS;
return sym;
}
/*
* "typeof" will have to merge the types together
*/
void dmrC_merge_type(struct symbol *sym, struct symbol *base_type)
{
sym->ctype.as |= base_type->ctype.as;
sym->ctype.modifiers |= (base_type->ctype.modifiers & ~MOD_STORAGE);
dmrC_concat_context_list(base_type->ctype.contexts,
&sym->ctype.contexts);
sym->ctype.base_type = base_type->ctype.base_type;
if (sym->ctype.base_type->type == SYM_NODE)
dmrC_merge_type(sym, sym->ctype.base_type);
}
static int count_array_initializer(struct global_symbols_t *S, struct symbol *t, struct expression *expr)
{
int nr = 0;
int is_char = 0;
/*
* Arrays of character types are special; they can be initialized by
* string literal _or_ by string literal in braces. The latter means
* that with T x[] = {<string literal>} number of elements in x depends
* on T - if it's a character type, we get the length of string literal
* (including NUL), otherwise we have one element here.
*/
if (t->ctype.base_type == &S->int_type && t->ctype.modifiers & MOD_CHAR)
is_char = 1;
switch (expr->type) {
case EXPR_INITIALIZER: {
struct expression *entry;
int count = 0;
int str_len = 0;
FOR_EACH_PTR(expr->expr_list, entry) {
count++;
switch (entry->type) {
case EXPR_INDEX:
if (entry->idx_to >= nr)
nr = entry->idx_to+1;
break;
case EXPR_PREOP: {
struct expression *e = entry;
if (is_char) {
while (e && e->type == EXPR_PREOP && e->op == '(')
e = e->unop;
if (e && e->type == EXPR_STRING) {
entry = e;
case EXPR_STRING:
if (is_char)
str_len = entry->string->length;
}
}
}
default:
nr++;
}
} END_FOR_EACH_PTR(entry);
if (count == 1 && str_len)
nr = str_len;
break;
}
case EXPR_PREOP:
if (is_char) {
struct expression *e = expr;
while (e && e->type == EXPR_PREOP && e->op == '(')
e = e->unop;
if (e && e->type == EXPR_STRING) {
expr = e;
case EXPR_STRING:
if (is_char)
nr = expr->string->length;
}
}
break;
default:
break;
}
return nr;
}
static struct expression *get_symbol_initializer(struct symbol *sym)
{
do {
if (sym->initializer)
return sym->initializer;
} while ((sym = sym->same_symbol) != NULL);
return NULL;
}
static struct symbol * examine_node_type(struct global_symbols_t *S, struct symbol *sym)
{
struct symbol *base_type = examine_base_type(S, sym);
int bit_size;
unsigned long alignment;
/* SYM_NODE - figure out what the type of the node was.. */
bit_size = 0;
alignment = 0;
if (!base_type)
return sym;
bit_size = base_type->bit_size;
alignment = base_type->ctype.alignment;
/* Pick up signedness information into the node */
sym->ctype.modifiers |= (MOD_SIGNEDNESS & base_type->ctype.modifiers);
if (!sym->ctype.alignment)
sym->ctype.alignment = alignment;
/* Unsized array? The size might come from the initializer.. */
if (bit_size < 0 && base_type->type == SYM_ARRAY) {
struct expression *initializer = get_symbol_initializer(sym);
if (initializer) {
struct symbol *node_type = base_type->ctype.base_type;
int count = count_array_initializer(S, node_type, initializer);
if (node_type && node_type->bit_size >= 0)
bit_size = dmrC_array_element_offset(S->C->target, node_type->bit_size, count);
/* Note that the bit_size will be set on parent SYM_NODE rather than here */
//base_type->bit_size = bit_size;
}
}
sym->bit_size = bit_size;
return sym;
}
static struct symbol *examine_enum_type(struct global_symbols_t *S, struct symbol *sym)
{
struct symbol *base_type = examine_base_type(S, sym);
sym->ctype.modifiers |= (base_type->ctype.modifiers & MOD_SIGNEDNESS);
sym->bit_size = S->C->target->bits_in_enum;
if (base_type->bit_size > sym->bit_size)
sym->bit_size = base_type->bit_size;
sym->ctype.alignment = S->C->target->enum_alignment;
if (base_type->ctype.alignment > sym->ctype.alignment)
sym->ctype.alignment = base_type->ctype.alignment;
return sym;
}
static struct symbol *examine_pointer_type(struct global_symbols_t *S, struct symbol *sym)
{
/*
* We need to set the pointer size first, and
* examine the thing we point to only afterwards.
* That's because this pointer type may end up
* being needed for the base type size evaluation.
*/
if (!sym->bit_size)
sym->bit_size = S->C->target->bits_in_pointer;
if (!sym->ctype.alignment)
sym->ctype.alignment = S->C->target->pointer_alignment;
return sym;
}
/*
* Fill in type size and alignment information for
* regular SYM_TYPE things.
*/
struct symbol *dmrC_examine_symbol_type(struct global_symbols_t *S, struct symbol * sym)
{
if (!sym)
return sym;
/* Already done? */
if (sym->examined)
return sym;
sym->examined = 1;
switch (sym->type) {
case SYM_FN:
case SYM_NODE:
return examine_node_type(S, sym);
case SYM_ARRAY:
return examine_array_type(S, sym);
case SYM_STRUCT:
return examine_struct_union_type(S, sym, 1);
case SYM_UNION:
return examine_struct_union_type(S, sym, 0);
case SYM_PTR:
return examine_pointer_type(S, sym);
case SYM_ENUM:
return examine_enum_type(S, sym);
case SYM_BITFIELD:
return examine_bitfield_type(S, sym);
case SYM_BASETYPE:
/* Size and alignment had better already be set up */
return sym;
case SYM_TYPEOF: {
struct symbol *base = dmrC_evaluate_expression(S->C, sym->initializer);
if (base) {
unsigned long mod = 0;
if (dmrC_is_bitfield_type(base))
dmrC_warning(S->C, base->pos, "typeof applied to bitfield type");
if (base->type == SYM_NODE) {
mod |= base->ctype.modifiers & MOD_TYPEOF;
base = base->ctype.base_type;
}
sym->type = SYM_NODE;
sym->ctype.modifiers = mod;
sym->ctype.base_type = base;
return examine_node_type(S, sym);
}
break;
}
case SYM_PREPROCESSOR:
dmrC_sparse_error(S->C, sym->pos, "ctype on preprocessor command? (%s)", dmrC_show_ident(S->C, sym->ident));
return NULL;
case SYM_UNINITIALIZED:
dmrC_sparse_error(S->C, sym->pos, "ctype on uninitialized symbol %p", sym);
return NULL;
case SYM_RESTRICT:
examine_base_type(S, sym);
return sym;
case SYM_FOULED:
examine_base_type(S, sym);
return sym;
default:
dmrC_sparse_error(S->C, sym->pos, "Examining unknown symbol type %d", sym->type);
break;
}
return sym;
}
const char* dmrC_get_type_name(enum type type)
{
const char *type_lookup[] = {
[SYM_UNINITIALIZED] = "uninitialized",
[SYM_PREPROCESSOR] = "preprocessor",
[SYM_BASETYPE] = "basetype",
[SYM_NODE] = "node",
[SYM_PTR] = "pointer",
[SYM_FN] = "function",
[SYM_ARRAY] = "array",
[SYM_STRUCT] = "struct",
[SYM_UNION] = "union",
[SYM_ENUM] = "enum",
[SYM_TYPEDEF] = "typedef",
[SYM_TYPEOF] = "typeof",
[SYM_MEMBER] = "member",
[SYM_BITFIELD] = "bitfield",
[SYM_LABEL] = "label",
[SYM_RESTRICT] = "restrict",
[SYM_FOULED] = "fouled",
[SYM_KEYWORD] = "keyword",
[SYM_BAD] = "bad"};
if (type <= SYM_BAD)
return type_lookup[type];
else
return NULL;
}
struct symbol *dmrC_examine_pointer_target(struct global_symbols_t *S, struct symbol *sym)
{
return examine_base_type(S, sym);
}
void dmrC_create_fouled(struct global_symbols_t *S, struct symbol *type)
{
if (type->bit_size < S->C->target->bits_in_int) {
struct symbol *news = dmrC_alloc_symbol(S, type->pos, type->type);
*news = *type;
news->bit_size = S->C->target->bits_in_int;
news->type = SYM_FOULED;
news->ctype.base_type = type;
dmrC_add_symbol(S->C, &S->restr, type);
dmrC_add_symbol(S->C, &S->fouled, news);
}
}
struct symbol *dmrC_befoul(struct global_symbols_t *S, struct symbol *type)
{
struct symbol *t1, *t2;
while (type->type == SYM_NODE)
type = type->ctype.base_type;
PREPARE_PTR_LIST(S->restr, t1);
PREPARE_PTR_LIST(S->fouled, t2);
for (;;) {
if (t1 == type)
return t2;
if (!t1)
break;
NEXT_PTR_LIST(t1);
NEXT_PTR_LIST(t2);
}
FINISH_PTR_LIST(t2);
FINISH_PTR_LIST(t1);
return NULL;
}
void dmrC_check_declaration(struct global_symbols_t *S, struct symbol *sym)
{
int warned = 0;
struct symbol *next = sym;
while ((next = next->next_id) != NULL) {
if (next->ns != sym->ns)
continue;
if (sym->scope == next->scope) {
sym->same_symbol = next;
return;
}
/* Extern in block level matches a TOPLEVEL non-static symbol */
if (sym->ctype.modifiers & MOD_EXTERN) {
if ((next->ctype.modifiers & (MOD_TOPLEVEL|MOD_STATIC)) == MOD_TOPLEVEL) {
sym->same_symbol = next;
return;
}
}
if (!S->C->Wshadow || warned)
continue;
if (dmrC_get_sym_type(next) == SYM_FN)
continue;
warned = 1;
dmrC_warning(S->C, sym->pos, "symbol '%s' shadows an earlier one", dmrC_show_ident(S->C, sym->ident));
dmrC_info(S->C, next->pos, "originally declared here");
}
}
void dmrC_bind_symbol(struct global_symbols_t *S, struct symbol *sym, struct ident *ident, enum namespace_type ns)
{
struct scope *scope;
if (sym->bound) {
dmrC_sparse_error(S->C, sym->pos, "internal error: symbol type already bound");
return;
}
if (ident->reserved && (ns & (NS_TYPEDEF | NS_STRUCT | NS_LABEL | NS_SYMBOL))) {
dmrC_sparse_error(S->C, sym->pos, "Trying to use reserved word '%s' as identifier", dmrC_show_ident(S->C, ident));
return;
}
sym->ns = ns;
sym->next_id = ident->symbols;
ident->symbols = sym;
if (sym->ident && sym->ident != ident)
dmrC_warning(S->C, sym->pos, "Symbol '%s' already bound", dmrC_show_ident(S->C, sym->ident));
sym->ident = ident;
sym->bound = 1;
scope = S->C->block_scope;
if (ns == NS_SYMBOL && dmrC_toplevel(S->C, scope)) {
unsigned mod = MOD_ADDRESSABLE | MOD_TOPLEVEL;
scope = S->C->global_scope;
if (sym->ctype.modifiers & MOD_STATIC ||
dmrC_is_extern_inline(sym)) {
scope = S->C->file_scope;
mod = MOD_TOPLEVEL;
}
sym->ctype.modifiers |= mod;
}
if (ns == NS_MACRO)
scope = S->C->file_scope;
if (ns == NS_LABEL)
scope = S->C->function_scope;
dmrC_bind_scope(S->C, sym, scope);
}
struct symbol *dmrC_create_symbol(struct global_symbols_t *S, int stream, const char *name, int type, int ns)
{
struct ident *ident = dmrC_built_in_ident(S->C, name);
struct symbol *sym = dmrC_lookup_symbol(ident, ns);
if (sym && sym->type != type)
dmrC_die(S->C, "symbol %s created with different types: %d old %d", name,
type, sym->type);
if (!sym) {
struct token *token = dmrC_built_in_token(S->C, stream, ident);
sym = dmrC_alloc_symbol(S, token->pos, type);
dmrC_bind_symbol(S, sym, token->ident, ns);
}
return sym;
}
void dmrC_init_symbols(struct dmr_C *C)
{
struct global_symbols_t *S = (struct global_symbols_t *) calloc(1, sizeof(struct global_symbols_t));
C->S = S;
S->C = C;
dmrC_allocator_init(&S->context_allocator, "contexts", sizeof(struct context), __alignof__(struct context),
CHUNK);
dmrC_allocator_init(&S->global_ident_allocator, "global_identifiers", sizeof(struct ident),
__alignof__(struct ident), CHUNK);
dmrC_allocator_init(&S->symbol_allocator, "symbols", sizeof(struct symbol),
__alignof__(struct symbol), CHUNK);
int stream = dmrC_init_stream(C, "builtin", -1, C->T->includepath);
#define __INIT_IDENT(n, str, res) (struct ident *) dmrC_allocator_allocate(&S->global_ident_allocator, sizeof(str)); S->n->len = sizeof(str)-1; memcpy(S->n->name, str, sizeof(str)); S->n->reserved = res;
#define __IDENT(n,str,res) \
{S->n = __INIT_IDENT(n, str, res)}
#include "ident-list.h"
#define __IDENT(n,str,res) \
dmrC_hash_ident(C, S->n)
#include "ident-list.h"
dmrC_init_parser(C, stream);
dmrC_init_builtins(C, stream);
}
void dmrC_destroy_symbols(struct dmr_C *C) {
/* tokenizer must be destroyed before this */
assert(C->T == NULL);
dmrC_destroy_parser(C);
assert(C->P == NULL);
struct global_symbols_t *S = C->S;
dmrC_allocator_destroy(&S->context_allocator);
dmrC_allocator_destroy(&S->global_ident_allocator);
dmrC_allocator_destroy(&S->symbol_allocator);
free(S);
C->S = NULL;
}
void dmrC_init_ctype(struct dmr_C *C)
{
assert(C);
struct global_symbols_t *S = C->S;
assert(S);
struct target_t *T = C->target;
assert(T);
const struct ctype_declare *ctype;
#ifdef _MSC_VER
if (sizeof(long long) == sizeof(size_t)) {
T->size_t_ctype = &S->ullong_ctype;
T->ssize_t_ctype = &S->llong_ctype;
}
else {
assert(sizeof(int) == sizeof(size_t));
T->size_t_ctype = &S->uint_ctype;
T->ssize_t_ctype = &S->int_ctype;
}
#else
T->size_t_ctype = &S->uint_ctype;
T->ssize_t_ctype = &S->int_ctype;
#endif
#define MOD_ESIGNED (MOD_SIGNED | MOD_EXPLICITLY_SIGNED)
#define MOD_LL (MOD_LONG | MOD_LONGLONG)
#define MOD_LLL MOD_LONGLONGLONG
const struct ctype_declare {
struct symbol *ptr;
enum type type;
unsigned long modifiers;
int *bit_size;
int *maxalign;
struct symbol *base_type;
} ctype_declaration[] = {
{ &S->bool_ctype, SYM_BASETYPE, MOD_UNSIGNED, &T->bits_in_bool, &T->max_int_alignment, &S->int_type },
{ &S->void_ctype, SYM_BASETYPE, 0, NULL, NULL, NULL },
{ &S->type_ctype, SYM_BASETYPE, MOD_TYPE, NULL, NULL, NULL },
{ &S->incomplete_ctype,SYM_BASETYPE, 0, NULL, NULL, NULL },
{ &S->bad_ctype, SYM_BASETYPE, 0, NULL, NULL, NULL },
{ &S->char_ctype, SYM_BASETYPE, MOD_SIGNED | MOD_CHAR, &T->bits_in_char, &T->max_int_alignment, &S->int_type },
{ &S->schar_ctype, SYM_BASETYPE, MOD_ESIGNED | MOD_CHAR, &T->bits_in_char, &T->max_int_alignment, &S->int_type },
{ &S->uchar_ctype, SYM_BASETYPE, MOD_UNSIGNED | MOD_CHAR, &T->bits_in_char, &T->max_int_alignment, &S->int_type },
{ &S->short_ctype, SYM_BASETYPE, MOD_SIGNED | MOD_SHORT, &T->bits_in_short, &T->max_int_alignment, &S->int_type },
{ &S->sshort_ctype, SYM_BASETYPE, MOD_ESIGNED | MOD_SHORT, &T->bits_in_short, &T->max_int_alignment, &S->int_type },
{ &S->ushort_ctype, SYM_BASETYPE, MOD_UNSIGNED | MOD_SHORT, &T->bits_in_short, &T->max_int_alignment, &S->int_type },
{ &S->int_ctype, SYM_BASETYPE, MOD_SIGNED, &T->bits_in_int, &T->max_int_alignment, &S->int_type },
{ &S->sint_ctype, SYM_BASETYPE, MOD_ESIGNED, &T->bits_in_int, &T->max_int_alignment, &S->int_type },
{ &S->uint_ctype, SYM_BASETYPE, MOD_UNSIGNED, &T->bits_in_int, &T->max_int_alignment, &S->int_type },
{ &S->long_ctype, SYM_BASETYPE, MOD_SIGNED | MOD_LONG, &T->bits_in_long, &T->max_int_alignment, &S->int_type },
{ &S->slong_ctype, SYM_BASETYPE, MOD_ESIGNED | MOD_LONG, &T->bits_in_long, &T->max_int_alignment, &S->int_type },
{ &S->ulong_ctype, SYM_BASETYPE, MOD_UNSIGNED | MOD_LONG, &T->bits_in_long, &T->max_int_alignment, &S->int_type },
{ &S->llong_ctype, SYM_BASETYPE, MOD_SIGNED | MOD_LL, &T->bits_in_longlong, &T->max_int_alignment, &S->int_type },
{ &S->sllong_ctype, SYM_BASETYPE, MOD_ESIGNED | MOD_LL, &T->bits_in_longlong, &T->max_int_alignment, &S->int_type },
{ &S->ullong_ctype, SYM_BASETYPE, MOD_UNSIGNED | MOD_LL, &T->bits_in_longlong, &T->max_int_alignment, &S->int_type },
{ &S->lllong_ctype, SYM_BASETYPE, MOD_SIGNED | MOD_LLL, &T->bits_in_longlonglong, &T->max_int_alignment, &S->int_type },
{ &S->slllong_ctype, SYM_BASETYPE, MOD_ESIGNED | MOD_LLL, &T->bits_in_longlonglong, &T->max_int_alignment, &S->int_type },
{ &S->ulllong_ctype, SYM_BASETYPE, MOD_UNSIGNED | MOD_LLL, &T->bits_in_longlonglong, &T->max_int_alignment, &S->int_type },
{ &S->float_ctype, SYM_BASETYPE, 0, &T->bits_in_float, &T->max_fp_alignment, &S->fp_type },
{ &S->double_ctype, SYM_BASETYPE, MOD_LONG, &T->bits_in_double, &T->max_fp_alignment, &S->fp_type },
{ &S->ldouble_ctype, SYM_BASETYPE, MOD_LONG | MOD_LONGLONG, &T->bits_in_longdouble, &T->max_fp_alignment, &S->fp_type },
{ &S->string_ctype, SYM_PTR, 0, &T->bits_in_pointer, &T->pointer_alignment, &S->char_ctype },
{ &S->ptr_ctype, SYM_PTR, 0, &T->bits_in_pointer, &T->pointer_alignment, &S->void_ctype },
{ &S->null_ctype, SYM_PTR, 0, &T->bits_in_pointer, &T->pointer_alignment, &S->void_ctype },
{ &S->label_ctype, SYM_PTR, 0, &T->bits_in_pointer, &T->pointer_alignment, &S->void_ctype },
{ &S->lazy_ptr_ctype, SYM_PTR, 0, &T->bits_in_pointer, &T->pointer_alignment, &S->void_ctype },
{ NULL, SYM_UNINITIALIZED, 0, NULL, NULL, NULL }
};
#undef MOD_LLL
#undef MOD_LL
#undef MOD_ESIGNED
for (ctype = ctype_declaration ; ctype->ptr; ctype++) {
struct symbol *sym = ctype->ptr;
unsigned long bit_size = ctype->bit_size ? *ctype->bit_size : -1;
unsigned long maxalign = ctype->maxalign ? *ctype->maxalign : 0;
unsigned long alignment = dmrC_bits_to_bytes(T, bit_size);
if (alignment > maxalign)
alignment = maxalign;
sym->type = ctype->type;
sym->bit_size = bit_size;
sym->ctype.alignment = alignment;
sym->ctype.base_type = ctype->base_type;
sym->ctype.modifiers = ctype->modifiers;
}
S->typenames[0].sym = &S->char_ctype; S->typenames[0].name = "char";
S->typenames[1].sym = &S->schar_ctype; S->typenames[1].name = "signed char";
S->typenames[2].sym = &S->uchar_ctype; S->typenames[2].name = "unsigned char";
S->typenames[3].sym = &S->short_ctype; S->typenames[3].name = "short";
S->typenames[4].sym = &S->sshort_ctype; S->typenames[4].name = "signed short";
S->typenames[5].sym = &S->ushort_ctype; S->typenames[5].name = "unsigned short";
S->typenames[6].sym = &S->int_ctype; S->typenames[6].name = "int";
S->typenames[7].sym = &S->sint_ctype; S->typenames[7].name = "signed int";
S->typenames[8].sym = &S->uint_ctype; S->typenames[8].name = "unsigned int";
S->typenames[9].sym = &S->slong_ctype; S->typenames[9].name = "signed long";
S->typenames[10].sym = &S->long_ctype; S->typenames[10].name = "long";
S->typenames[11].sym = &S->ulong_ctype; S->typenames[11].name = "unsigned long";
S->typenames[12].sym = &S->llong_ctype; S->typenames[12].name = "long long";
S->typenames[13].sym = &S->sllong_ctype; S->typenames[13].name = "signed long long";
S->typenames[14].sym = &S->ullong_ctype; S->typenames[14].name = "unsigned long long";
S->typenames[15].sym = &S->lllong_ctype; S->typenames[15].name = "long long long";
S->typenames[16].sym = &S->slllong_ctype; S->typenames[16].name = "signed long long long";
S->typenames[17].sym = &S->ulllong_ctype; S->typenames[17].name = "unsigned long long long";
S->typenames[18].sym = &S->void_ctype; S->typenames[18].name = "void";
S->typenames[19].sym = &S->bool_ctype; S->typenames[19].name = "bool";
S->typenames[20].sym = &S->string_ctype; S->typenames[20].name = "string";
S->typenames[21].sym = &S->float_ctype; S->typenames[21].name = "float";
S->typenames[22].sym = &S->double_ctype; S->typenames[22].name = "double";
S->typenames[23].sym = &S->ldouble_ctype; S->typenames[23].name = "long double";
S->typenames[24].sym = &S->incomplete_ctype; S->typenames[24].name = "incomplete type";
S->typenames[25].sym = &S->int_type; S->typenames[25].name = "abstract int";
S->typenames[26].sym = &S->fp_type; S->typenames[26].name = "abstract fp";
S->typenames[27].sym = &S->label_ctype; S->typenames[27].name = "label type";
S->typenames[28].sym = &S->bad_ctype; S->typenames[28].name = "bad type";
S->typenames[29].sym = NULL, S->typenames[29].name = NULL;
}

@ -0,0 +1,595 @@
#ifndef DMR_C_SYMBOL_H
#define DMR_C_SYMBOL_H
/*
* Basic symbol and namespace definitions.
*
* Copyright (C) 2003 Transmeta Corp.
* 2003 Linus Torvalds
*
* 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.
*/
/*
* This version is part of the dmr_c project.
* Copyright (C) 2017 Dibyendu Majumdar
*/
#include <target.h>
#include <token.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* An identifier with semantic meaning is a "symbol".
*
* There's a 1:n relationship: each symbol is always
* associated with one identifier, while each identifier
* can have one or more semantic meanings due to C scope
* rules.
*
* The progression is symbol -> token -> identifier. The
* token contains the information on where the symbol was
* declared.
*/
enum namespace_type {
NS_NONE = 0,
NS_MACRO = 1,
NS_TYPEDEF = 2,
NS_STRUCT = 4, // Also used for unions and enums.
NS_LABEL = 8,
NS_SYMBOL = 16,
NS_ITERATOR = 32,
NS_PREPROCESSOR = 64,
NS_UNDEF = 128,
NS_KEYWORD = 256,
};
enum type {
SYM_UNINITIALIZED,
SYM_PREPROCESSOR,
SYM_BASETYPE,
SYM_NODE,
SYM_PTR,
SYM_FN,
SYM_ARRAY,
SYM_STRUCT,
SYM_UNION,
SYM_ENUM,
SYM_TYPEDEF,
SYM_TYPEOF,
SYM_MEMBER,
SYM_BITFIELD,
SYM_LABEL,
SYM_RESTRICT,
SYM_FOULED,
SYM_KEYWORD,
SYM_BAD,
};
enum keyword {
KW_SPECIFIER = 1 << 0,
KW_MODIFIER = 1 << 1,
KW_QUALIFIER = 1 << 2,
KW_ATTRIBUTE = 1 << 3,
KW_STATEMENT = 1 << 4,
KW_ASM = 1 << 5,
KW_MODE = 1 << 6,
KW_SHORT = 1 << 7,
KW_LONG = 1 << 8,
KW_EXACT = 1 << 9,
};
struct context {
struct expression *context_expr;
unsigned int in, out;
};
DECLARE_PTR_LIST(context_list, struct context);
struct phi_map;
struct ctype {
unsigned long modifiers;
unsigned long alignment;
struct context_list *contexts;
unsigned int as;
struct symbol *base_type;
};
struct decl_state {
struct ctype ctype;
struct ident **ident;
struct symbol_op *mode;
unsigned char prefer_abstract, is_inline, storage_class, is_tls;
};
struct symbol;
DECLARE_PTR_LIST(symbol_list, struct symbol);
struct symbol_op {
enum keyword type;
int (*evaluate)(struct dmr_C *, struct expression *);
int (*expand)(struct dmr_C *, struct expression *, int);
int (*args)(struct dmr_C *, struct expression *);
/* keywords */
struct token *(*declarator)(struct dmr_C *, struct token *token,
struct decl_state *ctx);
struct token *(*statement)(struct dmr_C *, struct token *token, struct statement *stmt);
struct token *(*toplevel)(struct dmr_C *, struct token *token, struct symbol_list **list);
struct token *(*attribute)(struct dmr_C *, struct token *token, struct symbol *attr,
struct decl_state *ctx);
struct symbol *(*to_mode)(struct dmr_C *, struct symbol *);
int test, set, cls;
};
#define SYM_ATTR_WEAK 0
#define SYM_ATTR_NORMAL 1
#define SYM_ATTR_STRONG 2
struct symbol {
enum type type : 8;
enum namespace_type ns : 9;
unsigned char used : 1, attr : 2, enum_member : 1, bound : 1;
struct position pos; /* Where this symbol was declared */
struct position endpos; /* Where this symbol ends*/
struct ident *ident; /* What identifier this symbol is associated with */
struct symbol *next_id; /* Next semantic symbol that shares this identifier */
struct symbol *replace; /* What is this symbol shadowed by in copy-expression */
struct scope *scope;
union {
struct symbol *same_symbol;
struct symbol *next_subobject;
};
struct symbol_op *op;
union {
struct /* NS_MACRO */ {
struct token *expansion;
struct token *arglist;
struct scope *used_in;
};
struct /* NS_PREPROCESSOR */ {
int (*handler)(struct dmr_C *, struct stream *, struct token **, struct token *);
int normal;
};
struct /* NS_SYMBOL */ {
unsigned long offset;
int bit_size;
unsigned int bit_offset:8,
arg_count:10,
variadic:1,
initialized:1,
examined:1,
expanding:1,
evaluated:1,
string:1,
designated_init:1,
forced_arg:1,
transparent_union:1;
struct expression *array_size;
struct ctype ctype;
struct symbol_list *arguments;
struct statement *stmt;
struct symbol_list *symbol_list;
struct statement *inline_stmt;
struct symbol_list *inline_symbol_list;
struct expression *initializer;
struct entrypoint *ep;
long long value; /* Initial value */
struct symbol *definition;
};
};
union /* backend */ {
struct basic_block *bb_target; /* label */
void *aux; /* Auxiliary info, e.g. backend information */
struct { /* sparse ctags */
char kind;
unsigned char visited:1;
};
};
pseudo_t pseudo;
DMRC_BACKEND_TYPE priv;
};
/* Modifiers */
#define MOD_AUTO 0x0001
#define MOD_REGISTER 0x0002
#define MOD_STATIC 0x0004
#define MOD_EXTERN 0x0008
#define MOD_CONST 0x0010
#define MOD_VOLATILE 0x0020
#define MOD_SIGNED 0x0040
#define MOD_UNSIGNED 0x0080
#define MOD_CHAR 0x0100
#define MOD_SHORT 0x0200
#define MOD_LONG 0x0400
#define MOD_LONGLONG 0x0800
#define MOD_LONGLONGLONG 0x1000
#define MOD_PURE 0x2000
#define MOD_TYPEDEF 0x10000
#define MOD_TLS 0x20000
#define MOD_INLINE 0x40000
#define MOD_ADDRESSABLE 0x80000
#define MOD_NOCAST 0x100000
#define MOD_NODEREF 0x200000
#define MOD_ACCESSED 0x400000
#define MOD_TOPLEVEL 0x800000 // scoping..
#define MOD_ASSIGNED 0x2000000
#define MOD_TYPE 0x4000000
#define MOD_SAFE 0x8000000 // non-null/non-trapping pointer
#define MOD_USERTYPE 0x10000000
#define MOD_NORETURN 0x20000000
#define MOD_EXPLICITLY_SIGNED 0x40000000
#define MOD_BITWISE 0x80000000
#define MOD_NONLOCAL (MOD_EXTERN | MOD_TOPLEVEL)
#define MOD_STORAGE (MOD_AUTO | MOD_REGISTER | MOD_STATIC | MOD_EXTERN | MOD_INLINE | MOD_TOPLEVEL)
#define MOD_SIGNEDNESS (MOD_SIGNED | MOD_UNSIGNED | MOD_EXPLICITLY_SIGNED)
#define MOD_LONG_ALL (MOD_LONG | MOD_LONGLONG | MOD_LONGLONGLONG)
#define MOD_SPECIFIER (MOD_CHAR | MOD_SHORT | MOD_LONG_ALL | MOD_SIGNEDNESS)
#define MOD_SIZE (MOD_CHAR | MOD_SHORT | MOD_LONG_ALL)
#define MOD_IGNORE (MOD_TOPLEVEL | MOD_STORAGE | MOD_ADDRESSABLE | \
MOD_ASSIGNED | MOD_USERTYPE | MOD_ACCESSED | MOD_EXPLICITLY_SIGNED)
#define MOD_PTRINHERIT (MOD_VOLATILE | MOD_CONST | MOD_NODEREF | MOD_NORETURN | MOD_NOCAST)
/* modifiers preserved by typeof() operator */
#define MOD_TYPEOF (MOD_VOLATILE | MOD_CONST | MOD_NOCAST | MOD_SPECIFIER)
struct ctype_name {
struct symbol *sym;
const char *name;
};
struct global_symbols_t {
struct dmr_C *C;
/* Abstract types */
struct symbol int_type,
fp_type;
/* C types */
struct symbol bool_ctype, void_ctype, type_ctype,
char_ctype, schar_ctype, uchar_ctype,
short_ctype, sshort_ctype, ushort_ctype,
int_ctype, sint_ctype, uint_ctype,
long_ctype, slong_ctype, ulong_ctype,
llong_ctype, sllong_ctype, ullong_ctype,
lllong_ctype, slllong_ctype, ulllong_ctype,
float_ctype, double_ctype, ldouble_ctype,
string_ctype, ptr_ctype, lazy_ptr_ctype,
incomplete_ctype, label_ctype, bad_ctype,
null_ctype;
/* Special internal symbols */
struct symbol zero_int;
/*
* Secondary symbol list for stuff that needs to be output because it
* was used.
*/
struct symbol_list *translation_unit_used_list;
struct allocator context_allocator;
struct allocator symbol_allocator;
struct allocator global_ident_allocator;
struct symbol_list *restr, *fouled;
struct ctype_name typenames[30];
#define __IDENT(n, str, res) struct ident *n
#include "ident-list.h"
#undef __IDENT
};
extern void dmrC_init_symbols(struct dmr_C *C);
extern void dmrC_init_ctype(struct dmr_C *C);
extern void dmrC_init_builtins(struct dmr_C *C, int stream);
extern void dmrC_destroy_symbols(struct dmr_C *C);
extern struct context *dmrC_alloc_context(struct global_symbols_t *S);
extern void dmrC_access_symbol(struct global_symbols_t *S, struct symbol *sym);
extern const char *dmrC_type_difference(struct dmr_C *C, struct ctype *c1, struct ctype *c2,
unsigned long mod1, unsigned long mod2);
extern struct symbol *dmrC_lookup_symbol(struct ident *, enum namespace_type);
extern struct symbol *dmrC_create_symbol(struct global_symbols_t *S, int stream, const char *name, int type, int ns);
extern struct symbol *dmrC_alloc_symbol(struct global_symbols_t *S,
struct position pos, int type);
extern void dmrC_show_type(struct dmr_C *C, struct symbol *);
extern const char *dmrC_modifier_string(struct dmr_C *C, unsigned long mod);
extern void dmrC_show_symbol(struct dmr_C *C, struct symbol *);
extern int dmrC_show_symbol_expr_init(struct dmr_C *C, struct symbol *sym);
extern void dmrC_show_symbol_list(struct dmr_C *C, struct symbol_list *, const char *);
extern void dmrC_bind_symbol(struct global_symbols_t *S, struct symbol *sym,
struct ident *ident, enum namespace_type ns);
extern struct symbol *dmrC_examine_symbol_type(struct global_symbols_t *S,
struct symbol *sym);
extern struct symbol *dmrC_examine_pointer_target(struct global_symbols_t *S,
struct symbol *sym);
extern const char *dmrC_show_typename(struct dmr_C *C, struct symbol *sym);
extern const char *dmrC_builtin_typename(struct dmr_C *C, struct symbol *sym);
extern const char *dmrC_builtin_ctypename(struct dmr_C *C, struct ctype *ctype);
extern const char *dmrC_get_type_name(enum type type);
extern void dmrC_debug_symbol(struct dmr_C *C, struct symbol *);
extern void dmrC_merge_type(struct symbol *sym, struct symbol *base_type);
extern void dmrC_check_declaration(struct global_symbols_t *S, struct symbol *sym);
static inline struct symbol *dmrC_get_base_type(struct global_symbols_t *S,
const struct symbol *sym)
{
return dmrC_examine_symbol_type(S, sym->ctype.base_type);
}
static inline int dmrC_is_int_type(struct global_symbols_t *S,
const struct symbol *type)
{
if (type->type == SYM_NODE)
type = type->ctype.base_type;
if (type->type == SYM_ENUM)
type = type->ctype.base_type;
return type->type == SYM_BITFIELD ||
type->ctype.base_type == &S->int_type;
}
static inline int dmrC_is_enum_type(const struct symbol *type)
{
if (type->type == SYM_NODE)
type = type->ctype.base_type;
return (type->type == SYM_ENUM);
}
static inline int dmrC_is_type_type(struct symbol *type)
{
return (type->ctype.modifiers & MOD_TYPE) != 0;
}
static inline int dmrC_is_ptr_type(struct symbol *type)
{
if (type->type == SYM_NODE)
type = type->ctype.base_type;
return type->type == SYM_PTR || type->type == SYM_ARRAY || type->type == SYM_FN;
}
static inline int dmrC_is_func_type(struct symbol *type)
{
if (type->type == SYM_NODE)
type = type->ctype.base_type;
return type->type == SYM_FN;
}
static inline int dmrC_is_array_type(struct symbol *type)
{
if (type->type == SYM_NODE)
type = type->ctype.base_type;
return type->type == SYM_ARRAY;
}
static inline int dmrC_is_float_type(struct global_symbols_t *S, struct symbol *type)
{
if (type->type == SYM_NODE)
type = type->ctype.base_type;
return type->ctype.base_type == &S->fp_type;
}
static inline int dmrC_is_byte_type(const struct target_t *target,
struct symbol *type)
{
return type->bit_size == target->bits_in_char && type->type != SYM_BITFIELD;
}
static inline int dmrC_is_void_type(struct global_symbols_t *S, struct symbol *type)
{
if (type->type == SYM_NODE)
type = type->ctype.base_type;
return type == &S->void_ctype;
}
static inline int dmrC_is_bool_type(struct global_symbols_t *S, struct symbol *type)
{
if (type->type == SYM_NODE)
type = type->ctype.base_type;
return type == &S->bool_ctype;
}
static inline int dmrC_is_scalar_type(struct global_symbols_t *S, struct symbol *type)
{
if (type->type == SYM_NODE)
type = type->ctype.base_type;
switch (type->type) {
case SYM_ENUM:
case SYM_BITFIELD:
case SYM_PTR:
case SYM_ARRAY: // OK, will be a PTR after conversion
case SYM_FN:
case SYM_RESTRICT: // OK, always integer types
return 1;
default:
break;
}
if (type->ctype.base_type == &S->int_type)
return 1;
if (type->ctype.base_type == &S->fp_type)
return 1;
return 0;
}
// From Luc - sssa-mini
static inline int dmrC_is_simple_type(struct global_symbols_t *S, struct symbol *type)
{
if (type->type == SYM_NODE)
type = type->ctype.base_type;
switch (type->type) {
case SYM_ENUM:
case SYM_BITFIELD:
case SYM_PTR:
case SYM_RESTRICT: // OK, always integer types
return 1;
// Following is causing failures because the IR
// attempts to store values into unions or structs
//case SYM_STRUCT:
//case SYM_UNION:
// return type->bit_size <= S->long_ctype.bit_size;
default:
break;
}
if (type->ctype.base_type == &S->int_type)
return 1;
if (type->ctype.base_type == &S->fp_type)
return 1;
return 0;
}
// From Luc - sssa-mini
static inline int dmrC_is_simple_var(struct global_symbols_t *S, struct symbol *var)
{
if (!dmrC_is_simple_type(S, var))
return 0;
#define MOD_NONREG (MOD_STATIC|MOD_NONLOCAL|MOD_ADDRESSABLE|MOD_VOLATILE)
if (var->ctype.modifiers & MOD_NONREG)
return 0;
return 1;
}
static inline int dmrC_is_function(struct symbol *type)
{
return type && type->type == SYM_FN;
}
static inline int dmrC_is_extern_inline(struct symbol *sym)
{
return (sym->ctype.modifiers & MOD_EXTERN) &&
(sym->ctype.modifiers & MOD_INLINE) &&
dmrC_is_function(sym->ctype.base_type);
}
static inline int dmrC_is_toplevel(struct symbol *sym)
{
return (sym->ctype.modifiers & MOD_TOPLEVEL);
}
static inline int dmrC_is_extern(struct symbol *sym)
{
return (sym->ctype.modifiers & MOD_EXTERN);
}
static inline int dmrC_is_static(struct symbol *sym)
{
return (sym->ctype.modifiers & MOD_STATIC);
}
static int dmrC_is_signed_type(struct symbol *sym)
{
if (sym->type == SYM_NODE)
sym = sym->ctype.base_type;
if (sym->type == SYM_PTR)
return 0;
return !(sym->ctype.modifiers & MOD_UNSIGNED);
}
static inline int dmrC_is_unsigned(struct symbol *sym)
{
return !dmrC_is_signed_type(sym);
}
static inline int dmrC_get_sym_type(struct symbol *type)
{
if (type->type == SYM_NODE)
type = type->ctype.base_type;
if (type->type == SYM_ENUM)
type = type->ctype.base_type;
return type->type;
}
static inline struct symbol *dmrC_get_nth_symbol(struct symbol_list *list, unsigned int idx)
{
return (struct symbol *)ptrlist_nth_entry((struct ptr_list *)list, idx);
}
static inline struct symbol *dmrC_lookup_keyword(struct ident *ident,
enum namespace_type ns)
{
if (!ident->keyword)
return NULL;
return dmrC_lookup_symbol(ident, ns);
}
static inline void dmrC_concat_symbol_list(struct symbol_list *from, struct symbol_list **to)
{
ptrlist_concat((struct ptr_list *)from, (struct ptr_list **) to);
}
static inline void dmrC_add_symbol(struct dmr_C *C, struct symbol_list **list, struct symbol *sym)
{
ptrlist_add((struct ptr_list**)list, sym, &C->ptrlist_allocator);
}
static inline int dmrC_symbol_list_size(struct symbol_list *list)
{
return ptrlist_size((struct ptr_list *)list);
}
static inline void dmrC_concat_context_list(struct context_list *from,
struct context_list **to)
{
ptrlist_concat((struct ptr_list *)from, (struct ptr_list **)to);
}
static inline void dmrC_add_context(struct dmr_C *C, struct context_list **list,
struct context *ctx)
{
ptrlist_add((struct ptr_list **)list, ctx, &C->ptrlist_allocator);
}
static inline int dmrC_is_prototype(struct symbol *sym)
{
if (sym->type == SYM_NODE)
sym = sym->ctype.base_type;
return sym && sym->type == SYM_FN && !sym->stmt;
}
#define dmrC_is_restricted_type(type) (dmrC_get_sym_type(type) == SYM_RESTRICT)
#define dmrC_is_fouled_type(type) (dmrC_get_sym_type(type) == SYM_FOULED)
#define dmrC_is_bitfield_type(type) (dmrC_get_sym_type(type) == SYM_BITFIELD)
extern void dmrC_create_fouled(struct global_symbols_t *S, struct symbol *type);
extern struct symbol *dmrC_befoul(struct global_symbols_t *S, struct symbol *type);
#ifdef __cplusplus
}
#endif
#endif

@ -0,0 +1,88 @@
/*
* Copyright (C) 2003 Transmeta Corp.
* 2003 Linus Torvalds
*
* 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.
*/
/*
* This version is part of the dmr_c project.
* Copyright (C) 2017 Dibyendu Majumdar
*/
#include <stdio.h>
#include <stdlib.h>
#include <port.h>
#include <symbol.h>
#include <target.h>
enum dummy { DUMMY };
void dmrC_init_target(struct dmr_C *C) {
struct target_t *t = (struct target_t *)calloc(1, sizeof(struct target_t));
/*
* For "__attribute__((aligned))"
*/
t->max_alignment = 16;
/*
* Integer data types
*/
t->bits_in_bool = 1;
t->bits_in_char = 8;
t->bits_in_short = 16;
t->bits_in_int = 32;
t->bits_in_long = sizeof(long) * t->bits_in_char;
t->bits_in_longlong = 64;
t->bits_in_longlonglong = 128;
t->bits_in_wchar = 32;
t->max_int_alignment = __alignof__(long long);
/*
* Floating point data types
*/
t->bits_in_float = 32;
t->bits_in_double = 64;
t->bits_in_longdouble = sizeof(long double) * t->bits_in_char;
t->max_fp_alignment = 8;
/*
* Pointer data type
*/
t->bits_in_pointer = sizeof(void *) * t->bits_in_char;
t->pointer_alignment = __alignof__(void *);
/*
* Enum data types
*/
t->bits_in_enum = 32;
t->enum_alignment = 4;
C->target = t;
}
void dmrC_destroy_target(struct dmr_C *C) {
free(C->target);
C->target = NULL;
}

@ -0,0 +1,85 @@
#ifndef DMR_C_TARGET_H
#define DMR_C_TARGET_H
/*
* sparse/target.h
*
* Copyright (C) 2003 Transmeta Corp.
* 2003 Linus Torvalds
*/
/*
* This version is part of the dmr_c project.
* Copyright (C) 2017 Dibyendu Majumdar
*/
#include <lib.h>
struct target_t {
struct symbol *size_t_ctype;
struct symbol *ssize_t_ctype;
/*
* For "__attribute__((aligned))"
*/
int max_alignment;
/*
* Integer data types
*/
int bits_in_bool;
int bits_in_char;
int bits_in_short;
int bits_in_int;
int bits_in_long;
int bits_in_longlong;
int bits_in_longlonglong;
int bits_in_wchar;
int max_int_alignment;
/*
* Floating point data types
*/
int bits_in_float;
int bits_in_double;
int bits_in_longdouble;
int max_fp_alignment;
/*
* Pointer data type
*/
int bits_in_pointer;
int pointer_alignment;
/*
* Enum data types
*/
int bits_in_enum;
int enum_alignment;
};
/*
* Helper functions for converting bits to bytes and vice versa.
*/
static inline int dmrC_bits_to_bytes(const struct target_t *target, int bits) {
return bits >= 0 ? (bits + target->bits_in_char - 1) / target->bits_in_char : -1;
}
static inline int dmrC_bytes_to_bits(const struct target_t *target, int bytes) {
return bytes * target->bits_in_char;
}
static inline unsigned long dmrC_array_element_offset(const struct target_t *target, unsigned long base_bits, int idx)
{
int fragment = base_bits % target->bits_in_char;
if (fragment)
base_bits += target->bits_in_char - fragment;
return base_bits * idx;
}
extern void dmrC_init_target(struct dmr_C *C);
extern void dmrC_destroy_target(struct dmr_C *C);
#endif

@ -0,0 +1,294 @@
/*
* Basic tokenization structures. NOTE! Those tokens had better
* be pretty small, since we're going to keep them all in memory
* indefinitely.
*
* Copyright (C) 2003 Transmeta Corp.
* 2003 Linus Torvalds
*
* 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.
*/
/*
* This version is part of the dmr_c project.
* Copyright (C) 2017 Dibyendu Majumdar
*/
#ifndef DMR_C_TOKENIZER_H
#define DMR_C_TOKENIZER_H
#include <lib.h>
#include <sys/types.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* This describes the pure lexical elements (tokens), with
* no semantic meaning. In other words, an identifier doesn't
* have a type or meaning, it is only a specific string in
* the input stream.
*
* Semantic meaning is handled elsewhere.
*/
enum constantfile {
CONSTANT_FILE_MAYBE, // To be determined, not inside any #ifs in this file
CONSTANT_FILE_IFNDEF, // To be determined, currently inside #ifndef
CONSTANT_FILE_NOPE, // No
CONSTANT_FILE_YES // Yes
};
struct stream {
int fd;
const char *name;
const char *path; // input-file path - see set_stream_include_path()
const char **next_path;
/* Use these to check for "already parsed" */
enum constantfile constant;
int dirty, next_stream, once;
struct ident *protect;
struct token *ifndef;
struct token *top_if;
};
struct ident {
struct ident *next; /* Hash chain of identifiers */
struct symbol *symbols; /* Pointer to semantic meaning list */
unsigned char len; /* Length of identifier name */
unsigned char tainted:1,
reserved:1,
keyword:1;
char name[]; /* Actual identifier */
};
DECLARE_PTR_LIST(ident_list, struct ident);
enum e_token_type {
TOKEN_EOF,
TOKEN_ERROR,
TOKEN_IDENT,
TOKEN_ZERO_IDENT,
TOKEN_NUMBER,
TOKEN_CHAR,
TOKEN_CHAR_EMBEDDED_0,
TOKEN_CHAR_EMBEDDED_1,
TOKEN_CHAR_EMBEDDED_2,
TOKEN_CHAR_EMBEDDED_3,
TOKEN_WIDE_CHAR,
TOKEN_WIDE_CHAR_EMBEDDED_0,
TOKEN_WIDE_CHAR_EMBEDDED_1,
TOKEN_WIDE_CHAR_EMBEDDED_2,
TOKEN_WIDE_CHAR_EMBEDDED_3,
TOKEN_STRING,
TOKEN_WIDE_STRING,
TOKEN_SPECIAL,
TOKEN_STREAMBEGIN,
TOKEN_STREAMEND,
TOKEN_MACRO_ARGUMENT,
TOKEN_STR_ARGUMENT,
TOKEN_QUOTED_ARGUMENT,
TOKEN_CONCAT,
TOKEN_GNU_KLUDGE,
TOKEN_UNTAINT,
TOKEN_ARG_COUNT,
TOKEN_IF,
TOKEN_SKIP_GROUPS,
TOKEN_ELSE,
};
/* Combination tokens */
#define COMBINATION_STRINGS { \
"+=", "++", \
"-=", "--", "->", \
"*=", \
"/=", \
"%=", \
"<=", ">=", \
"==", "!=", \
"&&", "&=", \
"||", "|=", \
"^=", "##", \
"<<", ">>", "..", \
"<<=", ">>=", "...", \
"", \
"<", ">", "<=", ">=" \
}
extern unsigned char dmrC_combinations_[][4];
enum special_token {
SPECIAL_BASE = 256,
SPECIAL_ADD_ASSIGN = SPECIAL_BASE,
SPECIAL_INCREMENT,
SPECIAL_SUB_ASSIGN,
SPECIAL_DECREMENT,
SPECIAL_DEREFERENCE,
SPECIAL_MUL_ASSIGN,
SPECIAL_DIV_ASSIGN,
SPECIAL_MOD_ASSIGN,
SPECIAL_LTE,
SPECIAL_GTE,
SPECIAL_EQUAL,
SPECIAL_NOTEQUAL,
SPECIAL_LOGICAL_AND,
SPECIAL_AND_ASSIGN,
SPECIAL_LOGICAL_OR,
SPECIAL_OR_ASSIGN,
SPECIAL_XOR_ASSIGN,
SPECIAL_HASHHASH,
SPECIAL_LEFTSHIFT,
SPECIAL_RIGHTSHIFT,
SPECIAL_DOTDOT,
SPECIAL_SHL_ASSIGN,
SPECIAL_SHR_ASSIGN,
SPECIAL_ELLIPSIS,
SPECIAL_ARG_SEPARATOR,
SPECIAL_UNSIGNED_LT,
SPECIAL_UNSIGNED_GT,
SPECIAL_UNSIGNED_LTE,
SPECIAL_UNSIGNED_GTE,
};
struct string {
unsigned int length:31;
unsigned int immutable:1;
char data[];
};
/* will fit into 32 bits */
struct argcount {
unsigned normal:10;
unsigned quoted:10;
unsigned str:10;
unsigned vararg:1;
};
/*
* This is a very common data structure, it should be kept
* as small as humanly possible. Big (rare) types go as
* pointers.
*/
struct token {
struct position pos;
struct token *next;
union {
const char *number;
struct ident *ident;
unsigned int special;
struct string *string;
int argnum;
struct argcount count;
char embedded[4];
};
};
static inline struct token *dmrC_containing_token(struct token **p)
{
void *addr = (char *)p - ((char *)&((struct token *)0)->next - (char *)0);
return (struct token *)addr;
}
struct tokenizer_state_t {
unsigned int tabstop;
int input_stream_nr;
struct stream *input_streams;
int input_streams_allocated;
char special[256]; // identifies CR LF TAB
long cclass[257]; // character class
unsigned char hash_results[32][2]; // hashes compound operators
int code[32]; // token values for compound operators
char special_buffer[4];
char ident_buffer[256];
char string_buffer[4 * MAX_STRING + 3];
char char_buffer[MAX_STRING + 4];
char quote_buffer[2 * MAX_STRING + 6];
char token_buffer[256];
char quoted_token_buffer[256];
char number_buffer[4095];
char string_buffer2[MAX_STRING];
struct ident **hash_table;
int ident_hit, ident_miss, idents;
const char **includepath;
};
#define dmrC_token_type(x) ((x)->pos.type)
/*
* Last token in the stream - points to itself.
* This allows us to not test for NULL pointers
* when following the token->next chain..
*/
extern struct token dmrC_eof_token_entry_;
#define dmrC_eof_token(x) ((x) == &dmrC_eof_token_entry_)
extern void dmrC_init_tokenizer(struct dmr_C *C);
extern void dmrC_destroy_tokenizer(struct dmr_C *C);
extern int dmrC_init_stream(struct dmr_C *C, const char *name, int fd,
const char **next_path);
extern const char *dmrC_stream_name(struct dmr_C *C, int stream);
extern struct ident *dmrC_hash_ident(struct dmr_C *C, struct ident *ident);
extern struct ident *dmrC_built_in_ident(struct dmr_C *C, const char *name);
extern struct token *dmrC_built_in_token(struct dmr_C *C, int stream, struct ident *ident);
extern const char *dmrC_show_special(struct dmr_C *C, int val);
extern const char *dmrC_show_ident(struct dmr_C *C, const struct ident *ident);
extern const char *dmrC_show_string(struct dmr_C *C, const struct string *string);
extern const char *dmrC_show_token(struct dmr_C *C, const struct token *token);
extern const char *dmrC_quote_token(struct dmr_C *C, const struct token *token);
extern int *dmrC_hash_stream(const char *name);
extern struct token *dmrC_tokenize(struct dmr_C *C, const char *name, int fd,
struct token *endtoken, const char **next_path);
/* This function assumes that stream 0 is being used - so it is not suitable
for general use */
extern struct token *dmrC_tokenize_buffer(struct dmr_C *C, unsigned char *buffer,
unsigned long size,
struct token **endtoken);
/* This version allows a named stream to be created */
extern struct token *dmrC_tokenize_buffer_stream(struct dmr_C *C,
const char *name,
unsigned char *buffer,
unsigned long size,
struct token **endtoken);
extern void dmrC_show_identifier_stats(struct dmr_C *C);
extern struct token *dmrC_preprocess(struct dmr_C *C, struct token *);
extern void dmrC_init_preprocessor_state(struct dmr_C *C);
static inline int dmrC_match_op(struct token *token, unsigned int op)
{
return token->pos.type == TOKEN_SPECIAL && token->special == op;
}
static inline int dmrC_match_ident(struct token *token, struct ident *id)
{
return token->pos.type == TOKEN_IDENT && token->ident == id;
}
static inline void dmrC_add_ident(struct dmr_C *C, struct ident_list **list, struct ident *ident)
{
ptrlist_add((struct ptr_list **)list, ident, &C->ptrlist_allocator);
}
extern int dmrC_test_tokenizer();
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

@ -0,0 +1,148 @@
/*
* UnSSA - translate the SSA back to normal form.
*
* For now it's done by replacing to set of copies:
* 1) For each phi-node, replace all their phisrc by copies to a common
* temporary.
* 2) Replace all the phi-nodes by copies of the temporaries to the phi-node target.
* This is node to preserve the semantic of the phi-node (they should all "execute"
* simultaneously on entry in the basic block in which they belong).
*
* This is similar to the "Sreedhar method I" except that the copies to the
* temporaries are not placed at the end of the predecessor basic blocks, but
* at the place where the phi-node operands are defined.
* This is particulary easy since these copies are essentialy already present
* as the corresponding OP_PHISOURCE.
*
* While very simple this method create a lot more copies that really necessary.
* We eliminate some of these copies but most probably most of them are still
* useless.
* Ideally, "Sreedhar method III" should be used:
* "Translating Out of Static Single Assignment Form", V. C. Sreedhar, R. D.-C. Ju,
* D. M. Gillies and V. Santhanam. SAS'99, Vol. 1694 of Lecture Notes in Computer
* Science, Springer-Verlag, pp. 194-210, 1999.
* But for this we need precise liveness, on each %phi and not only on OP_PHI's
* target pseudos.
*
* Copyright (C) 2005 Luc Van Oostenryck
*/
#include <assert.h>
#include <port.h>
#include <lib.h>
#include <linearize.h>
#include <allocate.h>
#include <flow.h>
static inline int nbr_pseudo_users(pseudo_t p)
{
return ptrlist_size((struct ptr_list *)p->users);
}
static int simplify_phi_node(struct dmr_C *C, struct instruction *phi, pseudo_t tmp)
{
pseudo_t target = phi->target;
struct pseudo_user *pu;
pseudo_t src;
// verify if this phi can be simplified
FOR_EACH_PTR(phi->phi_list, src) {
struct instruction *def = src->def;
if (!def)
continue;
if (def->bb == phi->bb)
return 0;
} END_FOR_EACH_PTR(src);
// no need to make a copy of this one
// -> replace the target pseudo by the tmp
FOR_EACH_PTR(target->users, pu) {
dmrC_use_pseudo(C, pu->insn, tmp, pu->userp);
} END_FOR_EACH_PTR(pu);
phi->bb = NULL;
return 1;
}
static void replace_phi_node(struct dmr_C *C, struct instruction *phi)
{
pseudo_t tmp;
pseudo_t p;
tmp = dmrC_alloc_pseudo(C, NULL);
tmp->type = phi->target->type;
tmp->ident = phi->target->ident;
tmp->def = NULL; // defined by all the phisrc
// can we avoid to make of copy?
simplify_phi_node(C, phi, tmp);
// rewrite all it's phi_src to copy to a new tmp
FOR_EACH_PTR(phi->phi_list, p) {
struct instruction *def = p->def;
pseudo_t src;
if (p == VOID_PSEUDO(C))
continue;
assert(def->opcode == OP_PHISOURCE);
def->opcode = OP_COPY;
def->target = tmp;
// can we eliminate the copy?
src = def->phi_src;
if (src->type != PSEUDO_REG)
continue;
switch (nbr_pseudo_users(src)) {
struct instruction *insn;
case 1:
insn = src->def;
if (!insn)
break;
insn->target = tmp;
case 0:
dmrC_kill_instruction(C, def);
def->bb = NULL;
}
} END_FOR_EACH_PTR(p);
if (!phi->bb)
return;
// rewrite the phi node:
// phi %rt, ...
// to:
// copy %rt, %tmp
phi->opcode = OP_COPY;
dmrC_use_pseudo(C, phi, tmp, &phi->src);
}
static void rewrite_phi_bb(struct dmr_C *C, struct basic_block *bb)
{
struct instruction *insn;
// Replace all the phi-nodes by copies of a temporary
// (which represent the set of all the %phi that feed them).
// The target pseudo doesn't change.
FOR_EACH_PTR(bb->insns, insn) {
if (!insn->bb)
continue;
if (insn->opcode != OP_PHI)
continue;
replace_phi_node(C, insn);
} END_FOR_EACH_PTR(insn);
}
int dmrC_unssa(struct dmr_C *C, struct entrypoint *ep)
{
struct basic_block *bb;
FOR_EACH_PTR(ep->bbs, bb) {
rewrite_phi_bb(C, bb);
} END_FOR_EACH_PTR(bb);
return 0;
}

@ -0,0 +1,773 @@
#include <ctype.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <walksymbol.h>
static void walk_expression(struct dmr_C *C, struct expression *expr,
struct symbol_visitor *visitor);
static void walk_statement(struct dmr_C *C, struct statement *stmt,
struct symbol_visitor *visitor);
static void walk_symbol_expression(struct dmr_C *C, struct expression *expr,
struct symbol_visitor *visitor);
static void walk_assignment_expression(struct dmr_C *C, struct expression *expr,
struct symbol_visitor *visitor);
static void walk_binary_expression(struct dmr_C *C, struct expression *expr,
struct symbol_visitor *visitor);
static void walk_preop_expression(struct dmr_C *C, struct expression *expr,
struct symbol_visitor *visitor);
static void walk_postop_expression(struct dmr_C *C, struct expression *expr,
struct symbol_visitor *visitor);
static void walk_call_expression(struct dmr_C *C, struct expression *expr,
struct symbol_visitor *visitor);
static void walk_cast_expression(struct dmr_C *C, struct expression *expr, struct symbol_visitor *visitor);
static void walk_conditional_expression(struct dmr_C *C, struct expression *expr,
struct symbol_visitor *visitor);
static void walk_label_expression(struct dmr_C *C, struct expression *expr,
struct symbol_visitor *visitor);
static void walk_initializer_expression(struct dmr_C *C, struct expression *expr, struct symbol *ctype, struct symbol_visitor *visitor);
static void walk_label(struct dmr_C *C, struct symbol *label, struct symbol_visitor *visitor);
static void walk_return_statement(struct dmr_C *C, struct statement *stmt, struct symbol_visitor *visitor);
static void walk_iterator_statement(struct dmr_C *C, struct statement *stmt, struct symbol_visitor *visitor);
static void walk_switch_statement(struct dmr_C *C, struct statement *stmt,
struct symbol_visitor *visitor);
void walk_return_statement(struct dmr_C *C, struct statement *stmt, struct symbol_visitor *visitor)
{
struct expression *expr = stmt->ret_value;
struct symbol *target = stmt->ret_target;
if (expr && expr->ctype) {
walk_expression(C, expr, visitor);
}
visitor->begin_statement(visitor->data, STMT_GOTO);
dmrC_walk_symbol(C, target, visitor);
visitor->end_statement(visitor->data);
}
void walk_label(struct dmr_C *C, struct symbol *label, struct symbol_visitor *visitor)
{
visitor->begin_label(visitor->data, dmrC_show_ident(C, label->ident));
dmrC_walk_symbol(C, label, visitor);
visitor->end_label(visitor->data);
}
void walk_iterator_statement(struct dmr_C *C, struct statement *stmt, struct symbol_visitor *visitor)
{
struct statement *pre_statement = stmt->iterator_pre_statement;
struct expression *pre_condition = stmt->iterator_pre_condition;
struct statement *statement = stmt->iterator_statement;
struct statement *post_statement = stmt->iterator_post_statement;
struct expression *post_condition = stmt->iterator_post_condition;
dmrC_walk_symbol_list(C, stmt->iterator_syms, visitor);
if (pre_statement) {
visitor->begin_iterator_prestatement(visitor->data);
walk_statement(C, pre_statement, visitor);
visitor->end_iterator_prestatement(visitor->data);
}
if (pre_condition) {
visitor->begin_iterator_precondition(visitor->data);
walk_expression(C, pre_condition, visitor);
visitor->end_iterator_precondition(visitor->data);
}
visitor->begin_iterator_statement(visitor->data);
walk_statement(C, statement, visitor);
visitor->end_iterator_statement(visitor->data);
if (stmt->iterator_continue->used) {
walk_label(C, stmt->iterator_continue, visitor);
}
if (post_statement) {
visitor->begin_iterator_poststatement(visitor->data);
walk_statement(C, post_statement, visitor);
visitor->end_iterator_poststatement(visitor->data);
}
if (post_condition) {
visitor->begin_iterator_postcondition(visitor->data);
walk_expression(C, post_condition, visitor);
visitor->end_iterator_postcondition(visitor->data);
}
if (stmt->iterator_break->used) {
walk_label(C, stmt->iterator_break, visitor);
}
}
void walk_switch_statement(struct dmr_C *C, struct statement *stmt,
struct symbol_visitor *visitor)
{
walk_expression(C, stmt->switch_expression, visitor);
struct symbol *sym;
/*
* Debugging only: Check that the case list is correct
* by printing it out.
*
* This is where a _real_ back-end would go through the
* cases to decide whether to use a lookup table or a
* series of comparisons etc
*/
FOR_EACH_PTR(stmt->switch_case->symbol_list, sym) {
struct statement *case_stmt = sym->stmt;
struct expression *expr = case_stmt->case_expression;
struct expression *to = case_stmt->case_to;
if (!expr) {
visitor->begin_default_case(visitor->data);
}
else {
if (expr->type == EXPR_VALUE) {
if (to) {
if (to->type == EXPR_VALUE) {
visitor->begin_case_range(visitor->data, expr->value, to->value);
}
}
else {
visitor->begin_case_value(visitor->data, expr->value);
}
}
}
dmrC_walk_symbol(C, sym, visitor);
visitor->end_case(visitor->data);
} END_FOR_EACH_PTR(sym);
walk_statement(C, stmt->switch_statement, visitor);
if (stmt->switch_break->used)
walk_label(C, stmt->switch_break, visitor);
}
void walk_statement(struct dmr_C *C, struct statement *stmt,
struct symbol_visitor *visitor)
{
if (!stmt)
return;
visitor->begin_statement(visitor->data, stmt->type);
switch (stmt->type) {
case STMT_DECLARATION:
dmrC_walk_symbol_list(C, stmt->declaration, visitor);
break;
case STMT_RETURN:
walk_return_statement(C, stmt, visitor);
break;
case STMT_COMPOUND: {
struct statement *s;
//if (stmt->inline_fn) {
// dmrC_show_statement(C, stmt->args);
// printf("\tbegin_inline \t%s\n", dmrC_show_ident(C, stmt->inline_fn->ident));
//}
FOR_EACH_PTR(stmt->stmts, s) {
walk_statement(C, s, visitor);
} END_FOR_EACH_PTR(s);
if (stmt->ret) {
walk_label(C, stmt->ret, visitor);
}
//if (stmt->inline_fn)
// printf("\tend_inlined\t%s\n", dmrC_show_ident(C, stmt->inline_fn->ident));
break;
}
case STMT_EXPRESSION:
walk_expression(C, stmt->expression, visitor);
break;
case STMT_IF: {
struct expression *cond = stmt->if_conditional;
walk_expression(C, cond, visitor);
visitor->begin_if_then(visitor->data);
walk_statement(C, stmt->if_true, visitor);
visitor->end_if_then(visitor->data);
if (stmt->if_false) {
visitor->begin_if_else(visitor->data);
walk_statement(C, stmt->if_false, visitor);
visitor->end_if_else(visitor->data);
}
break;
}
case STMT_SWITCH:
walk_switch_statement(C, stmt, visitor);
break;
case STMT_CASE:
walk_label(C, stmt->case_label, visitor);
walk_statement(C, stmt->case_statement, visitor);
break;
case STMT_ITERATOR:
walk_iterator_statement(C, stmt, visitor);
break;
case STMT_NONE:
break;
case STMT_LABEL:
visitor->begin_label(visitor->data, dmrC_show_ident(C, stmt->label_identifier->ident));
dmrC_walk_symbol(C, stmt->label_identifier, visitor);
visitor->end_label(visitor->data);
walk_statement(C, stmt->label_statement, visitor);
break;
case STMT_GOTO:
if (stmt->goto_expression) {
walk_expression(C, stmt->goto_expression, visitor);
}
else {
dmrC_walk_symbol(C, stmt->goto_label, visitor);
}
break;
case STMT_ASM:
//printf("\tasm( .... )\n");
break;
case STMT_CONTEXT: {
//int val = dmrC_show_expression(C, stmt->expression);
//printf("\tcontext( %d )\n", val);
break;
}
case STMT_RANGE: {
//int val = dmrC_show_expression(C, stmt->range_expression);
//int low = dmrC_show_expression(C, stmt->range_low);
//int high = dmrC_show_expression(C, stmt->range_high);
//printf("\trange( %d %d-%d)\n", val, low, high);
break;
}
}
visitor->end_statement(visitor->data);
}
void walk_symbol_expression(struct dmr_C *C, struct expression *expr,
struct symbol_visitor *visitor)
{
assert(expr->type == EXPR_SYMBOL);
struct symbol *sym = expr->symbol;
if (!sym)
return;
dmrC_walk_symbol(C, sym, visitor);
}
void walk_assignment_expression(struct dmr_C *C, struct expression *expr,
struct symbol_visitor *visitor)
{
assert(expr->type == EXPR_ASSIGNMENT);
if (!expr->ctype)
return;
int op = expr->op;
visitor->begin_assignment_expression(visitor->data, expr->type, op);
walk_expression(C, expr->left, visitor);
walk_expression(C, expr->right, visitor);
visitor->end_assignment_expression(visitor->data);
}
void walk_binary_expression(struct dmr_C *C, struct expression *expr,
struct symbol_visitor *visitor)
{
assert(expr->type == EXPR_BINOP || expr->type == EXPR_COMPARE || expr->type == EXPR_LOGICAL);
if (!expr->ctype)
return;
int op = expr->op;
visitor->begin_binop_expression(visitor->data, expr->type, op);
walk_expression(C, expr->left, visitor);
walk_expression(C, expr->right, visitor);
visitor->end_binop_expression(visitor->data);
}
void walk_preop_expression(struct dmr_C *C, struct expression *expr,
struct symbol_visitor *visitor)
{
assert(expr->type == EXPR_PREOP);
visitor->begin_preop_expression(visitor->data, expr->type, expr->op);
walk_expression(C, expr->unop, visitor);
visitor->end_preop_expression(visitor->data);
}
void walk_postop_expression(struct dmr_C *C, struct expression *expr,
struct symbol_visitor *visitor)
{
assert(expr->type == EXPR_POSTOP);
visitor->begin_postop_expression(visitor->data, expr->type, expr->op);
walk_expression(C, expr->unop, visitor);
visitor->end_postop_expression(visitor->data);
}
void walk_call_expression(struct dmr_C *C, struct expression *expr,
struct symbol_visitor *visitor)
{
assert(expr->type == EXPR_CALL);
if (!expr->ctype) {
return;
}
struct symbol *direct;
struct expression *arg, *fn;
fn = expr->fn;
/* Remove dereference, if any */
direct = NULL;
if (fn->type == EXPR_PREOP) {
if (fn->unop->type == EXPR_SYMBOL) {
struct symbol *sym = fn->unop->symbol;
if (sym->ctype.base_type->type == SYM_FN)
direct = sym;
}
}
if (direct && !direct->aux) {
dmrC_walk_symbol(C, direct, visitor);
}
if (direct) {
visitor->begin_direct_call_expression(visitor->data, expr->type, dmrC_show_ident(C, direct->ident));
}
else {
visitor->begin_indirect_call_expression(visitor->data, expr->type);
walk_expression(C, fn, visitor);
}
int n = 0;
FOR_EACH_PTR(expr->args, arg) {
visitor->begin_callarg_expression(visitor->data, expr->type, ++n);
walk_expression(C, arg, visitor);
visitor->end_callarg_expression(visitor->data);
} END_FOR_EACH_PTR(arg);
visitor->end_call_expression(visitor->data);
}
void walk_cast_expression(struct dmr_C *C, struct expression *expr, struct symbol_visitor *visitor)
{
struct symbol *old_type, *new_type;
int oldbits, newbits;
int is_signed;
old_type = expr->cast_expression->ctype;
new_type = expr->cast_type;
oldbits = old_type->bit_size;
newbits = new_type->bit_size;
is_signed = dmrC_is_signed_type(old_type);
visitor->begin_cast_expression(visitor->data, expr->type, oldbits, newbits, !is_signed);
walk_expression(C, expr->cast_expression, visitor);
dmrC_walk_symbol(C, new_type, visitor);
visitor->end_cast_expression(visitor->data);
}
void walk_conditional_expression(struct dmr_C *C, struct expression *expr,
struct symbol_visitor *visitor)
{
visitor->begin_conditional_expression(visitor->data, expr->type);
walk_expression(C, expr->conditional, visitor);
walk_expression(C, expr->cond_true, visitor);
walk_expression(C, expr->cond_false, visitor);
visitor->end_conditional_expression(visitor->data);
}
void walk_label_expression(struct dmr_C *C, struct expression *expr,
struct symbol_visitor *visitor)
{
visitor->begin_label_expression(visitor->data, expr->type);
dmrC_walk_symbol(C, expr->label_symbol, visitor);
visitor->end_label_expression(visitor->data);
}
static void walk_initialization(struct dmr_C *C, struct symbol *sym, struct expression *expr, struct symbol_visitor *visitor)
{
if (!expr->ctype)
return;
visitor->begin_initialization(visitor->data, expr->type);
walk_expression(C, expr, visitor);
dmrC_walk_symbol(C, sym, visitor);
visitor->end_initialization(visitor->data);
}
static void walk_position_expression(struct dmr_C *C, struct expression *expr, struct symbol *base, struct symbol_visitor *visitor)
{
struct symbol *ctype = expr->init_expr->ctype;
int bit_offset;
bit_offset = ctype ? ctype->bit_offset : -1;
visitor->begin_expression_position(visitor->data, EXPR_POS, expr->init_offset, bit_offset,
dmrC_show_ident(C, base->ident));
walk_expression(C, expr->init_expr, visitor);
visitor->end_expression_position(visitor->data);
}
void walk_initializer_expression(struct dmr_C *C, struct expression *expr, struct symbol *ctype, struct symbol_visitor *visitor)
{
struct expression *entry;
FOR_EACH_PTR(expr->expr_list, entry) {
again:
// Nested initializers have their positions already
// recursively calculated - just output them too
if (entry->type == EXPR_INITIALIZER) {
walk_initializer_expression(C, entry, ctype, visitor);
continue;
}
// Initializer indexes and identifiers should
// have been evaluated to EXPR_POS
if (entry->type == EXPR_IDENTIFIER) {
visitor->do_expression_identifier(visitor->data, entry->type, dmrC_show_ident(C, entry->expr_ident));
entry = entry->ident_expression;
goto again;
}
if (entry->type == EXPR_INDEX) {
visitor->do_expression_index(visitor->data, entry->type, entry->idx_from, entry->idx_to);
entry = entry->idx_expression;
goto again;
}
if (entry->type == EXPR_POS) {
walk_position_expression(C, entry, ctype, visitor);
continue;
}
walk_initialization(C, ctype, entry, visitor);
} END_FOR_EACH_PTR(entry);
}
void walk_expression(struct dmr_C *C, struct expression *expr,
struct symbol_visitor *visitor)
{
if (!expr)
return;
if (!expr->ctype)
return;
visitor->begin_expression(visitor->data, expr->type);
switch (expr->type) {
case EXPR_CALL:
walk_call_expression(C, expr, visitor);
break;
case EXPR_ASSIGNMENT:
walk_assignment_expression(C, expr, visitor);
break;
case EXPR_COMMA:
// return show_comma(C, expr);
break;
case EXPR_BINOP:
case EXPR_COMPARE:
case EXPR_LOGICAL:
walk_binary_expression(C, expr, visitor);
break;
case EXPR_PREOP:
walk_preop_expression(C, expr, visitor);
break;
case EXPR_POSTOP:
walk_postop_expression(C, expr, visitor);
break;
case EXPR_SYMBOL:
walk_symbol_expression(C, expr, visitor);
break;
case EXPR_DEREF:
case EXPR_SIZEOF:
case EXPR_PTRSIZEOF:
case EXPR_ALIGNOF:
case EXPR_OFFSETOF:
break;
case EXPR_CAST:
case EXPR_FORCE_CAST:
case EXPR_IMPLIED_CAST:
walk_cast_expression(C, expr, visitor);
break;
case EXPR_VALUE:
visitor->int_literal(visitor->data, expr->value, expr->ctype->bit_size, expr->ctype->ctype.modifiers & MOD_UNSIGNED);
break;
case EXPR_FVALUE:
visitor->float_literal(visitor->data, expr->fvalue, expr->ctype->bit_size);
break;
case EXPR_STRING:
visitor->string_literal(visitor->data, dmrC_show_string(C, expr->string));
break;
case EXPR_INITIALIZER:
walk_initializer_expression(C, expr, expr->ctype, visitor);
break;
case EXPR_SELECT:
case EXPR_CONDITIONAL:
walk_conditional_expression(C, expr, visitor);
break;
case EXPR_STATEMENT:
// return show_statement_expr(C, expr);
break;
case EXPR_LABEL:
walk_label_expression(C, expr, visitor);
break;
case EXPR_SLICE:
// return show_slice(C, expr);
break;
// None of these should exist as direct expressions: they are
// only valid as sub-expressions of initializers.
case EXPR_POS:
case EXPR_IDENTIFIER:
case EXPR_INDEX:
case EXPR_TYPE:
break;
}
visitor->end_expression(visitor->data);
}
void dmrC_walk_symbol_list(struct dmr_C *C, struct symbol_list *list,
struct symbol_visitor *visitor)
{
struct symbol *sym;
FOR_EACH_PTR(list, sym) { dmrC_walk_symbol(C, sym, visitor); }
END_FOR_EACH_PTR(sym);
}
void dmrC_walk_symbol(struct dmr_C *C, struct symbol *sym,
struct symbol_visitor *visitor)
{
if (!sym)
return;
if (sym->type != SYM_BASETYPE) {
if (sym->aux) {
/* already visited */
const char *name = sym->ident ? dmrC_show_ident(C, sym->ident) : "";
visitor->reference_symbol(visitor->data, (uint64_t)sym->aux, name);
return;
}
visitor->id++;
sym->aux = (void *)visitor->id;
}
char name[80] = { 0 };
if (sym->ident)
snprintf(name, sizeof name, "%s",
dmrC_show_ident(C, sym->ident));
else if (sym->type == SYM_BASETYPE)
snprintf(name, sizeof name, "%s",
dmrC_builtin_typename(C, sym));
struct symbol_info syminfo = { .id = (uint64_t)sym->aux,
.name = name,
.symbol_namespace = sym->ns,
.symbol_type = sym->type,
.alignment = sym->ctype.alignment,
.pos = sym->pos,
.bit_size = sym->bit_size,
.offset = sym->offset };
if (sym->ns == NS_STRUCT && dmrC_is_bitfield_type(sym)) {
syminfo.bit_offset = sym->bit_offset;
}
if (sym->array_size) {
syminfo.array_size =
dmrC_get_expression_value(C, sym->array_size);
}
visitor->begin_symbol(visitor->data, &syminfo);
if (sym->type == SYM_STRUCT || sym->type == SYM_UNION) {
struct symbol *member;
visitor->begin_struct_members(visitor->data, &syminfo);
FOR_EACH_PTR(sym->symbol_list, member)
{
dmrC_walk_symbol(C, member, visitor);
}
END_FOR_EACH_PTR(member);
visitor->end_struct_members(visitor->data);
}
if (sym->type == SYM_FN) {
struct symbol *arg;
visitor->begin_func_arguments(visitor->data, &syminfo);
FOR_EACH_PTR(sym->arguments, arg)
{
dmrC_walk_symbol(C, arg, visitor);
}
END_FOR_EACH_PTR(member);
visitor->end_func_arguments(visitor->data);
}
// Is there a base type?
if (sym->type != SYM_BASETYPE && sym->ctype.base_type) {
if (sym->type == SYM_FN)
visitor->begin_func_returntype(visitor->data, &syminfo);
else
visitor->begin_basetype(visitor->data, &syminfo);
dmrC_walk_symbol(C, sym->ctype.base_type, visitor);
if (sym->type == SYM_FN)
visitor->end_func_returntype(visitor->data);
else
visitor->end_basetype(visitor->data);
}
if (sym->type == SYM_FN) {
if (sym->stmt) {
visitor->begin_func_body(visitor->data, &syminfo);
walk_statement(C, sym->stmt, visitor);
visitor->end_func_body(visitor->data);
}
}
if (sym->initializer) {
visitor->begin_initializer(visitor->data, &syminfo);
walk_expression(C, sym->initializer, visitor);
visitor->end_initializer(visitor->data);
}
visitor->end_symbol(visitor->data);
}
static void begin_symbol_default(void *data, struct symbol_info *syminfo) {}
static void end_symbol_default(void *data) {}
static void begin_members_default(void *data, struct symbol_info *syminfo) {}
static void end_members_default(void *data) {}
static void begin_arguments_default(void *data, struct symbol_info *syminfo) {}
static void end_arguments_default(void *data) {}
static void reference_symbol_default(void *data, uint64_t id, const char *name) {}
static void begin_body_default(void *data, struct symbol_info *syminfo) {}
static void end_body_default(void *data) {}
static void begin_func_returntype_default(void *data,
struct symbol_info *syminfo)
{
}
static void end_func_returntype_default(void *data)
{
}
static void begin_basetype_default(void *data, struct symbol_info *syminfo) {}
static void end_basetype_default(void *data) {}
static void begin_initializer_default(void *data, struct symbol_info *syminfo)
{
}
static void end_initializer_default(void *data) {}
static void string_expression_default(void *data, const char *str) {}
static void int_literal_default(void *data, long long value, int bit_size, bool is_unsigned) {}
static void float_literal_default(void *data, long double fvalue, int bit_size) {}
static void begin_statement_default(void *data, enum statement_type statement_type) {}
static void end_statement_default(void *data) {}
static void begin_expression_default(void *data, enum expression_type expr_type) {}
static void end_expression_default(void *data) {}
static void begin_assignment_expression_default(void *data, enum expression_type expr_type, int op) {}
static void end_assignment_expression_default(void *data) {}
static void begin_binop_expression_default(void *data, enum expression_type expr_type, int op) {}
static void end_binop_expression_default(void *data) {}
static void begin_preop_expression_default(void *data,
enum expression_type expr_type, int op) {}
static void end_preop_expression_default(void *data) {}
static void begin_postop_expression_default(void *data,
enum expression_type expr_type, int op) {}
static void end_postop_expression_default(void *data) {}
static void begin_direct_call_expression_default(void *data,
enum expression_type expr_type, const char *name) {}
static void begin_indirect_call_expression_default(void *data,
enum expression_type expr_type) {}
static void end_call_expression_default(void *data) {}
static void begin_callarg_expression_default(void *data,
enum expression_type expr_type,
int argpos) {}
static void end_callarg_expression_default(void *data) {}
static void begin_cast_expression_default(void *data,
enum expression_type expr_type,
int oldbits, int newbits,
bool is_unsigned) {}
static void end_cast_expression_default(void *data) {}
static void begin_conditional_expression_default(void *data, enum expression_type expr_type) {}
static void end_conditional_expression_default(void *data) {}
static void begin_label_expression_default(void *data, enum expression_type expr_type) {}
static void end_label_expression_default(void *data) {}
static void do_expression_identifier_default(void *data,
enum expression_type expr_type, const char *ident) {}
static void do_expression_index_default(void *data,
enum expression_type expr_type, unsigned from, unsigned to) {}
static void begin_expression_position_default(void *data,
enum expression_type expr_type, unsigned init_offset, int bit_offset, const char *ident) {}
static void end_expression_position_default(void *data) {}
static void begin_initialization_default(void *data,
enum expression_type expr_type) {}
static void end_initialization_default(void *data) {}
static void begin_label_default(void *data, const char *name) {}
static void end_label_default(void *data) {}
static void begin_iterator_prestatement_default(void *data) {}
static void end_iterator_prestatement_default(void *data) {}
static void begin_iterator_precondition_default(void *data) {}
static void end_iterator_precondition_default(void *data) {}
static void begin_iterator_statement_default(void *data) {}
static void end_iterator_statement_default(void *data) {}
static void begin_iterator_postcondition_default(void *data) {}
static void end_iterator_postcondition_default(void *data) {}
static void begin_iterator_poststatement_default(void *data) {}
static void end_iterator_poststatement_default(void *data) {}
static void begin_case_value_default(void *data, long long value) {}
static void begin_case_range_default(void *data, long long from, long long to) {}
static void begin_default_case_default(void *data) {}
static void end_case_default(void *data) {}
static void begin_if_then_default(void *data) {}
static void end_if_then_default(void *data) {}
static void begin_if_else_default(void *data) {}
static void end_if_else_default(void *data) {}
void dmrC_init_symbol_visitor(struct symbol_visitor *visitor)
{
visitor->data = NULL;
visitor->id = 0;
visitor->begin_symbol = begin_symbol_default;
visitor->end_symbol = end_symbol_default;
visitor->begin_struct_members = begin_members_default;
visitor->end_struct_members = end_members_default;
visitor->begin_func_arguments = begin_arguments_default;
visitor->end_func_arguments = end_arguments_default;
visitor->reference_symbol = reference_symbol_default;
visitor->begin_func_body = begin_body_default;
visitor->end_func_body = end_body_default;
visitor->begin_func_returntype = begin_func_returntype_default;
visitor->end_func_returntype = end_func_returntype_default;
visitor->begin_basetype = begin_basetype_default;
visitor->end_basetype = end_basetype_default;
visitor->begin_initializer = begin_initializer_default;
visitor->end_initializer = end_initializer_default;
visitor->string_literal = string_expression_default;
visitor->float_literal = float_literal_default;
visitor->int_literal = int_literal_default;
visitor->begin_statement = begin_statement_default;
visitor->end_statement = end_statement_default;
visitor->begin_expression = begin_expression_default;
visitor->end_expression = end_expression_default;
visitor->begin_assignment_expression = begin_assignment_expression_default;
visitor->end_assignment_expression = end_assignment_expression_default;
visitor->begin_binop_expression = begin_binop_expression_default;
visitor->end_binop_expression = end_binop_expression_default;
visitor->begin_preop_expression = begin_preop_expression_default;
visitor->end_preop_expression = end_preop_expression_default;
visitor->begin_postop_expression = begin_postop_expression_default;
visitor->end_postop_expression = end_postop_expression_default;
visitor->begin_direct_call_expression = begin_direct_call_expression_default;
visitor->begin_indirect_call_expression = begin_indirect_call_expression_default;
visitor->end_call_expression = end_call_expression_default;
visitor->begin_callarg_expression = begin_callarg_expression_default;
visitor->end_callarg_expression = end_callarg_expression_default;
visitor->begin_cast_expression = begin_cast_expression_default;
visitor->end_cast_expression = end_cast_expression_default;
visitor->begin_conditional_expression = begin_conditional_expression_default;
visitor->end_conditional_expression = end_conditional_expression_default;
visitor->begin_label_expression = begin_label_expression_default;
visitor->end_label_expression = end_label_expression_default;
visitor->do_expression_identifier = do_expression_identifier_default;
visitor->do_expression_index = do_expression_index_default;
visitor->begin_expression_position = begin_expression_position_default;
visitor->end_expression_position = end_expression_position_default;
visitor->begin_initialization = begin_initialization_default;
visitor->end_initialization = end_initialization_default;
visitor->begin_label = begin_label_default;
visitor->end_label = end_label_default;
visitor->begin_iterator_prestatement = begin_iterator_prestatement_default;
visitor->end_iterator_prestatement = end_iterator_prestatement_default;
visitor->begin_iterator_precondition = begin_iterator_precondition_default;
visitor->end_iterator_precondition = end_iterator_precondition_default;
visitor->begin_iterator_statement = begin_iterator_statement_default;
visitor->end_iterator_statement = end_iterator_statement_default;
visitor->begin_iterator_postcondition = begin_iterator_postcondition_default;
visitor->end_iterator_postcondition = end_iterator_postcondition_default;
visitor->begin_iterator_poststatement = begin_iterator_poststatement_default;
visitor->end_iterator_poststatement = end_iterator_poststatement_default;
visitor->begin_case_value = begin_case_value_default;
visitor->begin_case_range = begin_case_range_default;
visitor->begin_default_case = begin_default_case_default;
visitor->end_case = end_case_default;
visitor->begin_if_then = begin_if_then_default;
visitor->end_if_then = end_if_then_default;
visitor->begin_if_else = begin_if_else_default;
visitor->end_if_else = end_if_else_default;
}

@ -0,0 +1,144 @@
#ifndef DMR_C_PARSETREE_H
#define DMR_C_PARSETREE_H
#include <allocate.h>
#include <lib.h>
#include <expression.h>
#include <parse.h>
#include <port.h>
#include <symbol.h>
#include <token.h>
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
struct symbol_info {
uint64_t id;
enum namespace_type symbol_namespace;
enum type symbol_type;
const char *name;
int bit_size;
unsigned long alignment;
unsigned int offset;
int bit_offset;
long long array_size;
struct position pos;
};
struct symbol_visitor {
void *data;
uint64_t id;
void (*begin_symbol)(void *data, struct symbol_info *syminfo);
void (*end_symbol)(void *data);
void (*begin_struct_members)(void *data, struct symbol_info *syminfo);
void (*end_struct_members)(void *data);
void (*begin_func_arguments)(void *data, struct symbol_info *syminfo);
void (*end_func_arguments)(void *data);
void (*reference_symbol)(void *data, uint64_t id, const char *name);
void (*begin_func_body)(void *data, struct symbol_info *syminfo);
void (*end_func_body)(void *data);
void (*begin_func_returntype)(void *data, struct symbol_info *syminfo);
void (*end_func_returntype)(void *data);
void (*begin_basetype)(void *data, struct symbol_info *syminfo);
void (*end_basetype)(void *data);
void (*begin_initializer)(void *data, struct symbol_info *syminfo);
void (*end_initializer)(void *data);
void (*string_literal)(void *data, const char *str);
void (*int_literal)(void *data, long long value, int bit_size,
bool is_unsigned);
void (*float_literal)(void *data, long double fvalue, int bit_size);
void (*begin_statement)(void *data, enum statement_type statement_type);
void (*end_statement)(void *data);
void (*begin_expression)(void *data, enum expression_type expr_type);
void (*end_expression)(void *data);
void (*begin_assignment_expression)(void *data,
enum expression_type expr_type,
int op);
void (*end_assignment_expression)(void *data);
void (*begin_binop_expression)(void *data,
enum expression_type expr_type, int op);
void (*end_binop_expression)(void *data);
void (*begin_preop_expression)(void *data,
enum expression_type expr_type, int op);
void (*end_preop_expression)(void *data);
void (*begin_postop_expression)(void *data,
enum expression_type expr_type, int op);
void (*end_postop_expression)(void *data);
void (*begin_direct_call_expression)(void *data,
enum expression_type expr_type,
const char *name);
void (*begin_indirect_call_expression)(void *data,
enum expression_type expr_type);
void (*end_call_expression)(void *data);
void (*begin_callarg_expression)(void *data,
enum expression_type expr_type,
int argpos);
void (*end_callarg_expression)(void *data);
void (*begin_cast_expression)(void *data,
enum expression_type expr_type,
int oldbits, int newbits,
bool is_unsigned);
void (*end_cast_expression)(void *data);
void (*begin_conditional_expression)(void *data,
enum expression_type expr_type);
void (*end_conditional_expression)(void *data);
void (*begin_label_expression)(void *data,
enum expression_type expr_type);
void (*end_label_expression)(void *data);
void (*do_expression_identifier)(void *data,
enum expression_type expr_type,
const char *ident);
void (*do_expression_index)(void *data, enum expression_type expr_type,
unsigned from, unsigned to);
void (*begin_expression_position)(void *data,
enum expression_type expr_type,
unsigned init_offset, int bit_offset,
const char *ident);
void (*end_expression_position)(void *data);
void (*begin_initialization)(void *data,
enum expression_type expr_type);
void (*end_initialization)(void *data);
void (*begin_label)(void *data, const char *name);
void (*end_label)(void *data);
void(*begin_iterator_prestatement)(void *data);
void(*end_iterator_prestatement)(void *data);
void(*begin_iterator_precondition)(void *data);
void(*end_iterator_precondition)(void *data);
void(*begin_iterator_statement)(void *data);
void(*end_iterator_statement)(void *data);
void(*begin_iterator_postcondition)(void *data);
void(*end_iterator_postcondition)(void *data);
void(*begin_iterator_poststatement)(void *data);
void(*end_iterator_poststatement)(void *data);
void(*begin_case_value)(void *data, long long value);
void(*begin_case_range)(void *data, long long from, long long to);
void(*begin_default_case)(void *data);
void(*end_case)(void *data);
void(*begin_if_then)(void *data);
void(*end_if_then)(void *data);
void(*begin_if_else)(void *data);
void(*end_if_else)(void *data);
};
extern void dmrC_init_symbol_visitor(struct symbol_visitor *visitor);
extern void dmrC_walk_symbol_list(struct dmr_C *C, struct symbol_list *list,
struct symbol_visitor *visitor);
extern void dmrC_walk_symbol(struct dmr_C *C, struct symbol *sym,
struct symbol_visitor *visitor);
#ifdef __cplusplus
}
#endif
#endif

@ -34,9 +34,7 @@
#include "lualib.h"
#include "lauxlib.h"
#if USE_DMR_C
LUAMOD_API int raviopen_dmrcluaapi(lua_State *L);
#endif
/*
** these libs are loaded by lua.c and are readily available to any Lua
@ -57,9 +55,7 @@ static const luaL_Reg loadedlibs[] = {
#ifdef USE_LLVM
{LUA_LLVMLIBNAME, raviopen_llvmluaapi},
#endif
#if USE_DMR_C
{ "dmrc", raviopen_dmrcluaapi },
#endif
#if defined(LUA_COMPAT_BITLIB)
{LUA_BITLIBNAME, luaopen_bit32},
#endif

File diff suppressed because it is too large Load Diff

@ -46,379 +46,339 @@
#include <lualib.h>
struct parser_state {
lua_State *L;
struct dmr_C *C;
struct allocator int_allocator;
int idcount;
int tabidx;
int stack[30];
int stackpos;
lua_State *L;
struct dmr_C *C;
struct allocator int_allocator;
int idcount;
int tabidx;
int stack[30];
int stackpos;
};
static void push_tabindex(struct parser_state *S)
{
assert(S->stackpos >= -1 && S->stackpos < 28);
S->stackpos++;
S->stack[S->stackpos] = S->tabidx;
S->tabidx = 1;
static void push_tabindex(struct parser_state *S) {
assert(S->stackpos >= -1 && S->stackpos < 28);
S->stackpos++;
S->stack[S->stackpos] = S->tabidx;
S->tabidx = 1;
}
static void pop_tabindex(struct parser_state *S)
{
assert(S->stackpos >= 0);
S->tabidx = S->stack[S->stackpos];
S->stackpos--;
static void pop_tabindex(struct parser_state *S) {
assert(S->stackpos >= 0);
S->tabidx = S->stack[S->stackpos];
S->stackpos--;
}
static void *visited(struct parser_state *S, int id) {
int *p = (int *)dmrC_allocator_allocate(&S->int_allocator, 0);
*p = id;
return p;
int *p = (int *)dmrC_allocator_allocate(&S->int_allocator, 0);
*p = id;
return p;
}
static void examine_symbol(struct parser_state *S, struct symbol *sym);
static void newProp(struct parser_state *S, const char *name, const char *value)
{
lua_pushstring(S->L, name);
lua_pushstring(S->L, value);
lua_settable(S->L, -3);
static void newProp(struct parser_state *S, const char *name,
const char *value) {
lua_pushstring(S->L, name);
lua_pushstring(S->L, value);
lua_settable(S->L, -3);
}
static void newNumProp(struct parser_state *S, const char *name, int value)
{
lua_pushstring(S->L, name);
lua_pushinteger(S->L, value);
lua_settable(S->L, -3);
static void newNumProp(struct parser_state *S, const char *name, int value) {
lua_pushstring(S->L, name);
lua_pushinteger(S->L, value);
lua_settable(S->L, -3);
}
static void newIdProp(struct parser_state *S, const char *name, unsigned int id)
{
char buf[256];
snprintf(buf, 256, "_%d", id);
newProp(S, name, buf);
static void newIdProp(struct parser_state *S, const char *name,
unsigned int id) {
char buf[256];
snprintf(buf, 256, "_%d", id);
newProp(S, name, buf);
}
static void popNamedTable(struct parser_state *S, const char *name)
{
lua_assert(lua_istable(S->L, -1));
lua_assert(lua_istable(S->L, -2));
pop_tabindex(S);
lua_pushstring(S->L, name);
lua_pushvalue(S->L, -2); /* top table */
lua_settable(S->L, -4); /* bottom table */
lua_pop(S->L, 1); /* pop top table */
static void popNamedTable(struct parser_state *S, const char *name) {
lua_assert(lua_istable(S->L, -1));
lua_assert(lua_istable(S->L, -2));
pop_tabindex(S);
lua_pushstring(S->L, name);
lua_pushvalue(S->L, -2); /* top table */
lua_settable(S->L, -4); /* bottom table */
lua_pop(S->L, 1); /* pop top table */
}
static void popTable(struct parser_state *S)
{
lua_assert(lua_istable(S->L, -1));
lua_assert(lua_istable(S->L, -2));
pop_tabindex(S);
int id = S->tabidx++;
lua_seti(S->L, -2, id); /* bottom table */
static void popTable(struct parser_state *S) {
lua_assert(lua_istable(S->L, -1));
lua_assert(lua_istable(S->L, -2));
pop_tabindex(S);
int id = S->tabidx++;
lua_seti(S->L, -2, id); /* bottom table */
}
static void new_sym_node(struct parser_state *S, struct symbol *sym, const char *name)
{
const char *ident = dmrC_show_ident(S->C, sym->ident);
assert(name != NULL);
assert(sym != NULL);
lua_newtable(S->L);
push_tabindex(S);
newNumProp(S, "id", S->idcount);
newProp(S, "type", name);
if (sym->ident && ident)
newProp(S, "ident", ident);
newProp(S, "file", dmrC_stream_name(S->C, sym->pos.stream));
newNumProp(S, "startline", sym->pos.line);
newNumProp(S, "startcol", sym->pos.pos);
if (sym->endpos.type) {
newNumProp(S, "endline", sym->endpos.line);
newNumProp(S, "endcol", sym->endpos.pos);
if (sym->pos.stream != sym->endpos.stream)
newProp(S, "endfile", dmrC_stream_name(S->C, sym->endpos.stream));
}
sym->aux = visited(S, S->idcount);
S->idcount++;
static void new_sym_node(struct parser_state *S, struct symbol *sym,
const char *name) {
const char *ident = dmrC_show_ident(S->C, sym->ident);
assert(name != NULL);
assert(sym != NULL);
lua_newtable(S->L);
push_tabindex(S);
newNumProp(S, "id", S->idcount);
newProp(S, "type", name);
if (sym->ident && ident) newProp(S, "ident", ident);
newProp(S, "file", dmrC_stream_name(S->C, sym->pos.stream));
newNumProp(S, "startline", sym->pos.line);
newNumProp(S, "startcol", sym->pos.pos);
if (sym->endpos.type) {
newNumProp(S, "endline", sym->endpos.line);
newNumProp(S, "endcol", sym->endpos.pos);
if (sym->pos.stream != sym->endpos.stream)
newProp(S, "endfile", dmrC_stream_name(S->C, sym->endpos.stream));
}
sym->aux = visited(S, S->idcount);
S->idcount++;
}
static void examine_members(struct parser_state *S, struct symbol_list *list)
{
struct symbol *sym;
static void examine_members(struct parser_state *S, struct symbol_list *list) {
struct symbol *sym;
FOR_EACH_PTR(list, sym) {
examine_symbol(S, sym);
} END_FOR_EACH_PTR(sym);
FOR_EACH_PTR(list, sym) { examine_symbol(S, sym); }
END_FOR_EACH_PTR(sym);
}
static void examine_modifiers(struct parser_state *S, struct symbol *sym)
{
struct mod_name {
unsigned long mod;
const char *name;
} * m;
static struct mod_name mod_names[] = {
{MOD_AUTO, "auto"},
{MOD_REGISTER, "register"},
{MOD_STATIC, "static"},
{MOD_EXTERN, "extern"},
{MOD_CONST, "const"},
{MOD_VOLATILE, "volatile"},
{MOD_SIGNED, "signed"},
{MOD_UNSIGNED, "unsigned"},
{MOD_CHAR, "char"},
{MOD_SHORT, "short"},
{MOD_LONG, "long"},
{MOD_LONGLONG, "long long"},
{MOD_LONGLONGLONG, "long long long"},
{MOD_TYPEDEF, "typedef"},
{MOD_TLS, "tls"},
{MOD_INLINE, "inline"},
{MOD_ADDRESSABLE, "addressable"},
{MOD_NOCAST, "nocast"},
{MOD_NODEREF, "noderef"},
{MOD_ACCESSED, "accessed"},
{MOD_TOPLEVEL, "toplevel"},
{MOD_ASSIGNED, "assigned"},
{MOD_TYPE, "type"},
{MOD_SAFE, "safe"},
{MOD_USERTYPE, "usertype"},
{MOD_NORETURN, "noreturn"},
{MOD_EXPLICITLY_SIGNED, "explicitly-signed"},
{MOD_BITWISE, "bitwise"},
{MOD_PURE, "pure"},
};
if (sym->ns != NS_SYMBOL)
return;
for (int i = 0; i < ARRAY_SIZE(mod_names); i++) {
m = mod_names + i;
if (sym->ctype.modifiers & m->mod) {
newNumProp(S, m->name, 1);
}
}
if (dmrC_is_prototype(sym))
newNumProp(S, "prototype", 1);
static void examine_modifiers(struct parser_state *S, struct symbol *sym) {
struct mod_name {
unsigned long mod;
const char *name;
} * m;
static struct mod_name mod_names[] = {
{MOD_AUTO, "auto"},
{MOD_REGISTER, "register"},
{MOD_STATIC, "static"},
{MOD_EXTERN, "extern"},
{MOD_CONST, "const"},
{MOD_VOLATILE, "volatile"},
{MOD_SIGNED, "signed"},
{MOD_UNSIGNED, "unsigned"},
{MOD_CHAR, "char"},
{MOD_SHORT, "short"},
{MOD_LONG, "long"},
{MOD_LONGLONG, "long long"},
{MOD_LONGLONGLONG, "long long long"},
{MOD_TYPEDEF, "typedef"},
{MOD_TLS, "tls"},
{MOD_INLINE, "inline"},
{MOD_ADDRESSABLE, "addressable"},
{MOD_NOCAST, "nocast"},
{MOD_NODEREF, "noderef"},
{MOD_ACCESSED, "accessed"},
{MOD_TOPLEVEL, "toplevel"},
{MOD_ASSIGNED, "assigned"},
{MOD_TYPE, "type"},
{MOD_SAFE, "safe"},
{MOD_USERTYPE, "usertype"},
{MOD_NORETURN, "noreturn"},
{MOD_EXPLICITLY_SIGNED, "explicitly-signed"},
{MOD_BITWISE, "bitwise"},
{MOD_PURE, "pure"},
};
if (sym->ns != NS_SYMBOL) return;
for (int i = 0; i < ARRAY_SIZE(mod_names); i++) {
m = mod_names + i;
if (sym->ctype.modifiers & m->mod) { newNumProp(S, m->name, 1); }
}
if (dmrC_is_prototype(sym)) newNumProp(S, "prototype", 1);
}
static void
examine_layout(struct parser_state *S, struct symbol *sym)
{
dmrC_examine_symbol_type(S->C->S, sym);
newNumProp(S, "bitsize", sym->bit_size);
newNumProp(S, "alignment", sym->ctype.alignment);
newNumProp(S, "offset", sym->offset);
if (dmrC_is_bitfield_type(sym)) {
newNumProp(S, "bitoffset", sym->bit_offset);
}
static void examine_layout(struct parser_state *S, struct symbol *sym) {
dmrC_examine_symbol_type(S->C->S, sym);
newNumProp(S, "bitsize", sym->bit_size);
newNumProp(S, "alignment", sym->ctype.alignment);
newNumProp(S, "offset", sym->offset);
if (dmrC_is_bitfield_type(sym)) {
newNumProp(S, "bitoffset", sym->bit_offset);
}
}
static void examine_symbol(struct parser_state *S, struct symbol *sym)
{
const char *base;
int array_size;
if (!sym)
return;
if (sym->aux) /*already visited */
return;
if (sym->ident && sym->ident->reserved)
return;
int savedpos = lua_gettop(S->L);
new_sym_node(S, sym, dmrC_get_type_name(sym->type));
examine_modifiers(S, sym);
examine_layout(S, sym);
if (sym->ctype.base_type) {
if ((base = dmrC_builtin_typename(S->C, sym->ctype.base_type)) == NULL) {
if (!sym->ctype.base_type->aux) {
examine_symbol(S, sym->ctype.base_type);
}
newNumProp(S, "basetype", *((int *)sym->ctype.base_type->aux));
} else {
newProp(S, "builtintype", base);
}
}
if (sym->array_size) {
/* TODO: modify dmrC_get_expression_value to give error return */
array_size = dmrC_get_expression_value(S->C, sym->array_size);
newNumProp(S, "arraysize", array_size);
}
switch (sym->type) {
case SYM_STRUCT:
case SYM_UNION:
examine_members(S, sym->symbol_list);
break;
static void examine_symbol(struct parser_state *S, struct symbol *sym) {
const char *base;
int array_size;
if (!sym) return;
if (sym->aux) /*already visited */
return;
if (sym->ident && sym->ident->reserved) return;
int savedpos = lua_gettop(S->L);
new_sym_node(S, sym, dmrC_get_type_name(sym->type));
examine_modifiers(S, sym);
examine_layout(S, sym);
if (sym->ctype.base_type) {
if ((base = dmrC_builtin_typename(S->C, sym->ctype.base_type)) == NULL) {
if (!sym->ctype.base_type->aux) {
examine_symbol(S, sym->ctype.base_type);
}
newNumProp(S, "basetype", *((int *)sym->ctype.base_type->aux));
}
else {
newProp(S, "builtintype", base);
}
}
if (sym->array_size) {
/* TODO: modify dmrC_get_expression_value to give error return */
array_size = dmrC_get_expression_value(S->C, sym->array_size);
newNumProp(S, "arraysize", array_size);
}
switch (sym->type) {
case SYM_STRUCT:
case SYM_UNION: examine_members(S, sym->symbol_list); break;
case SYM_FN: {
int savedpos2 = lua_gettop(S->L);
lua_newtable(S->L);
push_tabindex(S);
examine_members(S, sym->arguments);
popNamedTable(S, "arguments");
//examine_members(C, sym->symbol_list);
lua_assert(savedpos2 == lua_gettop(S->L));
break;
int savedpos2 = lua_gettop(S->L);
lua_newtable(S->L);
push_tabindex(S);
examine_members(S, sym->arguments);
popNamedTable(S, "arguments");
// examine_members(C, sym->symbol_list);
lua_assert(savedpos2 == lua_gettop(S->L));
break;
}
case SYM_UNINITIALIZED:
newProp(S, "builtintype", dmrC_builtin_typename(S->C, sym));
break;
default:
break;
}
popTable(S);
lua_assert(savedpos == lua_gettop(S->L));
return;
case SYM_UNINITIALIZED:
newProp(S, "builtintype", dmrC_builtin_typename(S->C, sym));
break;
default: break;
}
popTable(S);
lua_assert(savedpos == lua_gettop(S->L));
return;
}
static struct position *get_expansion_end (struct token *token)
{
struct token *p1, *p2;
static struct position *get_expansion_end(struct token *token) {
struct token *p1, *p2;
for (p1=NULL, p2=NULL;
!dmrC_eof_token(token);
p2 = p1, p1 = token, token = token->next);
for (p1 = NULL, p2 = NULL; !dmrC_eof_token(token);
p2 = p1, p1 = token, token = token->next)
;
if (p2)
return &(p2->pos);
else
return NULL;
if (p2)
return &(p2->pos);
else
return NULL;
}
static void examine_macro(struct parser_state *S, struct symbol *sym)
{
struct position *pos;
static void examine_macro(struct parser_state *S, struct symbol *sym) {
struct position *pos;
/* this should probably go in the main codebase*/
pos = get_expansion_end(sym->expansion);
if (pos)
sym->endpos = *pos;
else
sym->endpos = sym->pos;
/* this should probably go in the main codebase*/
pos = get_expansion_end(sym->expansion);
if (pos)
sym->endpos = *pos;
else
sym->endpos = sym->pos;
new_sym_node(S, sym, "macro");
new_sym_node(S, sym, "macro");
}
static void examine_namespace(struct parser_state *S, struct symbol *sym)
{
if (sym->ident && sym->ident->reserved)
return;
switch(sym->ns) {
case NS_MACRO:
examine_macro(S, sym);
break;
case NS_TYPEDEF:
case NS_STRUCT:
case NS_SYMBOL:
examine_symbol(S, sym);
break;
case NS_NONE:
case NS_LABEL:
case NS_ITERATOR:
case NS_UNDEF:
case NS_PREPROCESSOR:
case NS_KEYWORD:
break;
default:
break;
//dmrC_die(S->C, "Unrecognised namespace type %d",sym->ns);
}
static void examine_namespace(struct parser_state *S, struct symbol *sym) {
if (sym->ident && sym->ident->reserved) return;
switch (sym->ns) {
case NS_MACRO: examine_macro(S, sym); break;
case NS_TYPEDEF:
case NS_STRUCT:
case NS_SYMBOL: examine_symbol(S, sym); break;
case NS_NONE:
case NS_LABEL:
case NS_ITERATOR:
case NS_UNDEF:
case NS_PREPROCESSOR:
case NS_KEYWORD: break;
default:
break;
// dmrC_die(S->C, "Unrecognised namespace type %d",sym->ns);
}
}
static int get_stream_id(struct dmr_C *C, const char *name) {
int i;
for (i = 0; i < C->T->input_stream_nr; i++) {
if (strcmp(name, dmrC_stream_name(C, i)) == 0) return i;
}
return -1;
}
static int get_stream_id (struct dmr_C *C, const char *name)
{
int i;
for (i=0; i<C->T->input_stream_nr; i++) {
if (strcmp(name, dmrC_stream_name(C, i))==0)
return i;
}
return -1;
static void clean_up_symbols(struct dmr_C *C, struct symbol_list *list) {
struct symbol *sym;
FOR_EACH_PTR(list, sym) { dmrC_expand_symbol(C, sym); }
END_FOR_EACH_PTR(sym);
}
static void examine_symbol_list(struct parser_state *S, int stream_id, struct symbol_list *list)
{
struct symbol *sym;
if (!list)
return;
FOR_EACH_PTR(list, sym) {
if (sym->pos.stream == stream_id)
examine_namespace(S, sym);
} END_FOR_EACH_PTR(sym);
static void examine_symbol_list(struct parser_state *S, int stream_id,
struct symbol_list *list) {
struct symbol *sym;
if (!list) return;
clean_up_symbols(S->C, list);
FOR_EACH_PTR(list, sym) {
if (sym->pos.stream == stream_id) examine_namespace(S, sym);
}
END_FOR_EACH_PTR(sym);
}
static int dmrC_getsymbols(lua_State *L)
{
struct symbol_list *symlist;
struct string_list *filelist = NULL;
char *file;
struct dmr_C *C = new_dmr_C();
const char *codebuffer = luaL_checkstring(L, 1);
char *argv[] = { NULL };
int argc = 0;
symlist = dmrC_sparse_initialize(C, argc, argv, &filelist);
struct parser_state parser_state = {
.L = L,
.C = C,
.idcount = 0,
.stack = {0},
.stackpos = -1,
.tabidx = 1
};
dmrC_allocator_init(&parser_state.int_allocator, "integers", sizeof(int), __alignof__(int), CHUNK);
lua_newtable(L);
int luastack = lua_gettop(L);
push_tabindex(&parser_state);
#if 0
FOR_EACH_PTR(filelist, file) {
int fd = get_stream_id(C, file);
examine_symbol_list(C, fd, symlist);
dmrC_sparse_keep_tokens(C, file);
examine_symbol_list(C, fd, C->file_scope->symbols);
examine_symbol_list(C, fd, C->global_scope->symbols);
} END_FOR_EACH_PTR(file);
#endif
char *buffer = strdup(codebuffer);
if (dmrC_sparse_buffer(C, "buffer", buffer, 1)) {
int fd = get_stream_id(C, "buffer");
examine_symbol_list(&parser_state, fd, C->file_scope->symbols);
examine_symbol_list(&parser_state, fd, C->global_scope->symbols);
}
free(buffer);
static int dmrC_getsymbols(lua_State *L) {
struct symbol_list *symlist;
struct string_list *filelist = NULL;
char *file;
struct dmr_C *C = new_dmr_C();
const char *codebuffer = luaL_checkstring(L, 1);
char *argv[] = {NULL};
int argc = 0;
symlist = dmrC_sparse_initialize(C, argc, argv, &filelist);
// Simplification
clean_up_symbols(C, symlist);
struct parser_state parser_state = {
.L = L, .C = C, .idcount = 0, .stack = {0}, .stackpos = -1, .tabidx = 1};
dmrC_allocator_init(&parser_state.int_allocator, "integers", sizeof(int),
__alignof__(int), CHUNK);
lua_newtable(L);
int luastack = lua_gettop(L);
push_tabindex(&parser_state);
char *buffer = strdup(codebuffer);
dmrC_sparse_buffer(C, "buffer", buffer, 1);
int fd = get_stream_id(C, "buffer");
examine_symbol_list(&parser_state, fd, C->file_scope->symbols);
examine_symbol_list(&parser_state, fd, C->global_scope->symbols);
free(buffer);
destroy_dmr_C(C);
dmrC_allocator_destroy(&parser_state.int_allocator);
destroy_dmr_C(C);
dmrC_allocator_destroy(&parser_state.int_allocator);
lua_assert(luastack == lua_gettop(L));
lua_assert(luastack == lua_gettop(L));
return 1;
return 1;
}
static const luaL_Reg dmrclib[] = {
{ "getsymbols", dmrC_getsymbols },{ NULL, NULL } };
static const luaL_Reg dmrclib[] = {{"getsymbols", dmrC_getsymbols},
{NULL, NULL}};
LUAMOD_API int raviopen_dmrcluaapi(lua_State *L) {
luaL_newlib(L, dmrclib);
return 1;
luaL_newlib(L, dmrclib);
return 1;
}

Loading…
Cancel
Save