summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorManuel Mohr <manuel.mohr@kit.edu>2012-11-21 17:13:04 +0100
committerManuel Mohr <manuel.mohr@kit.edu>2012-11-21 17:13:04 +0100
commit7c6cd91cc5a2bef0b9f4555250c1266cf07d0da5 (patch)
tree1e8e48844020f5bff2cdf9d22fac02e6c05ffe60
parent567d5c4cd549111c8d939aeac7a4becf406452e2 (diff)
parente7314352be09a6e1f3735a0a80f2c044221d00dc (diff)
Merge branch 'master' into icore-merge
Conflicts: libfirm
-rw-r--r--Makefile83
-rw-r--r--adt/error.h10
-rw-r--r--ast.c141
-rw-r--r--ast.h6
-rw-r--r--ast2firm.c815
-rw-r--r--ast2firm.h3
-rw-r--r--ast_t.h10
-rw-r--r--attribute.c10
-rw-r--r--diagnostic.c28
-rw-r--r--driver/firm_opt.c113
-rw-r--r--driver/firm_timing.c11
-rw-r--r--entity.c2
-rw-r--r--entity_t.h13
-rw-r--r--input.c14
-rw-r--r--jump_target.c65
-rw-r--r--jump_target.h28
m---------libfirm0
-rw-r--r--main.c184
-rw-r--r--mangle.c2
-rw-r--r--parser.c389
-rw-r--r--preprocessor.c72
-rw-r--r--separator_t.h31
-rw-r--r--string_rep.c7
-rw-r--r--string_rep.h3
-rw-r--r--token.c7
-rw-r--r--type.c35
-rw-r--r--types.c20
-rw-r--r--types.h8
-rw-r--r--walk.c8
-rw-r--r--wrappergen/write_fluffy.c29
-rw-r--r--wrappergen/write_jna.c25
31 files changed, 1185 insertions, 987 deletions
diff --git a/Makefile b/Makefile
index 19548d1..1ff2ea3 100644
--- a/Makefile
+++ b/Makefile
@@ -1,10 +1,14 @@
-GOAL = $(BUILDDIR)/cparser
-
# include user-defined makefile settings
-include config.mak
-BUILDDIR ?= build
-variant ?= debug# Different libfirm variants (debug, optimize, profile)
+top_srcdir ?=
+top_builddir ?= build
+
+variant ?= debug# Different libfirm variants (debug, optimize, profile, coverage)
+srcdir ?= $(top_srcdir)
+builddir ?= $(top_builddir)/$(variant)
+
+#VPATH = $(srcdir)
# Use libfirm subdir if it exists, otherwise use pkg-config
ifneq ("$(wildcard libfirm)", "")
@@ -22,15 +26,18 @@ endif
CPPFLAGS = -I.
CPPFLAGS += $(FIRM_CPPFLAGS)
-CFLAGS += -Wall -W -Wstrict-prototypes -Wmissing-prototypes -std=c99 -pedantic
-CFLAGS_debug = -O0 -g
+CFLAGS += -Wall -W -Wstrict-prototypes -Wmissing-prototypes -std=c99
+CFLAGS_debug = -O0 -g
CFLAGS_optimize = -O3 -fomit-frame-pointer -DNDEBUG
-CFLAGS_profile = -pg -O3 -fno-inline
+CFLAGS_profile = -pg -O3 -fno-inline
+CFLAGS_coverage = --coverage -O0
CFLAGS += $(CFLAGS_$(variant))
-LFLAGS += $(FIRM_LIBS)
+LINKFLAGS_profile = -pg
+LINKFLAGS_coverage = --coverage
+LINKFLAGS += $(LINKFLAGS_$(variant)) $(FIRM_LIBS)
-SOURCES := \
+cparser_SOURCES = \
adt/strset.c \
adt/strutil.c \
adt/pset_new.c \
@@ -47,6 +54,7 @@ SOURCES := \
entitymap.c \
format_check.c \
input.c \
+ jump_target.c \
main.c \
mangle.c \
preprocessor.c \
@@ -63,25 +71,28 @@ SOURCES := \
wrappergen/write_fluffy.c \
wrappergen/write_jna.c \
wrappergen/write_compoundsizes.c
+cparser_OBJECTS = $(cparser_SOURCES:%.c=$(builddir)/%.o)
+cparser_DEPS = $(cparser_OBJECTS:%.o=%.d)
-OBJECTS = $(SOURCES:%.c=$(BUILDDIR)/%.o)
-DEPENDS = $(OBJECTS:%.o=%.d)
-
-SPLINTS = $(addsuffix .splint, $(SOURCES))
-CPARSERS = $(addsuffix .cparser, $(SOURCES))
-CPARSEROS = $(SOURCES:%.c=$(BUILDDIR)/cpb/%.o)
-CPARSEROS_E = $(SOURCES:%.c=$(BUILDDIR)/cpbe/%.o)
-CPARSEROS2 = $(SOURCES:%.c=$(BUILDDIR)/cpb2/%.o)
+SPLINTS = $(addsuffix .splint, $(cparser_SOURCES))
+CPARSERS = $(addsuffix .cparser, $(cparser_SOURCES))
+CPARSEROS = $(cparser_SOURCES:%.c=$(builddir)/cpb/%.o)
+CPARSEROS_E = $(cparser_SOURCES:%.c=$(builddir)/cpbe/%.o)
+CPARSEROS2 = $(cparser_SOURCES:%.c=$(builddir)/cpb2/%.o)
Q = @
+GOAL = $(builddir)/cparser
all: $(GOAL)
-.PHONY: all bootstrap bootstrap2 bootstrape clean selfcheck splint libfirm_subdir
+# disable make builtin suffix rules
+.SUFFIXES:
+
+-include $(cparser_DEPS)
--include $(DEPENDS)
+.PHONY: all bootstrap bootstrap2 bootstrape clean selfcheck splint libfirm_subdir
-$(SOURCES): config.h
+$(cparser_SOURCES): config.h
config.h:
cp config.h.in $@
@@ -96,12 +107,12 @@ UNUSED := $(shell \
echo "$$REV" | cmp -s - revision.h 2> /dev/null || echo "$$REV" > revision.h \
)
-DIRS := $(sort $(dir $(OBJECTS)))
-UNUSED := $(shell mkdir -p $(DIRS) $(DIRS:$(BUILDDIR)/%=$(BUILDDIR)/cpb/%) $(DIRS:$(BUILDDIR)/%=$(BUILDDIR)/cpb2/%) $(DIRS:$(BUILDDIR)/%=$(BUILDDIR)/cpbe/%))
+DIRS := $(sort $(dir $(cparser_OBJECTS)))
+UNUSED := $(shell mkdir -p $(DIRS) $(DIRS:$(builddir)/%=$(builddir)/cpb/%) $(DIRS:$(builddir)/%=$(builddir)/cpb2/%) $(DIRS:$(builddir)/%=$(builddir)/cpbe/%))
-$(GOAL): $(LIBFIRM_FILE) $(OBJECTS)
+$(GOAL): $(LIBFIRM_FILE) $(cparser_OBJECTS)
@echo "===> LD $@"
- $(Q)$(CC) $(OBJECTS) $(LIBFIRM_FILE) -o $(GOAL) $(LFLAGS)
+ $(Q)$(CC) $(cparser_OBJECTS) $(LIBFIRM_FILE) -o $(GOAL) $(LINKFLAGS)
ifneq ("$(LIBFIRM_FILE)", "")
ifneq ("$(MAKECMDGOALS)", "clean")
@@ -132,34 +143,34 @@ bootstrap2: cparser.bootstrap2
@echo '===> CPARSER $<'
$(Q)./cparser $(CPPFLAGS) -fsyntax-only $<
-$(BUILDDIR)/cpb/%.o: %.c $(BUILDDIR)/cparser
+$(builddir)/cpb/%.o: %.c $(builddir)/cparser
@echo '===> CPARSER $<'
- $(Q)./$(BUILDDIR)/cparser $(CPPFLAGS) -std=c99 -Wall -g3 -c $< -o $@
+ $(Q)./$(builddir)/cparser $(CPPFLAGS) -std=c99 -Wall -g3 -c $< -o $@
-$(BUILDDIR)/cpbe/%.o: %.c
- @echo '===> ECCP $<'
+$(builddir)/cpbe/%.o: %.c
+ @echo '===> ECCP $@'
$(Q)eccp $(CPPFLAGS) -std=c99 -Wall -c $< -o $@
-$(BUILDDIR)/cpb2/%.o: %.c cparser.bootstrap
+$(builddir)/cpb2/%.o: %.c cparser.bootstrap
@echo '===> CPARSER.BOOTSTRAP $<'
$(Q)./cparser.bootstrap $(CPPFLAGS) -Wall -g -c $< -o $@
cparser.bootstrap: $(CPARSEROS)
@echo "===> LD $@"
- $(Q)./$(BUILDDIR)/cparser $(CPARSEROS) $(LFLAGS) -o $@
+ $(Q)./$(builddir)/cparser $(CPARSEROS) $(LINKFLAGS) -o $@
cparser.bootstrape: $(CPARSEROS_E)
@echo "===> LD $@"
- $(Q)gcc $(CPARSEROS_E) $(LFLAGS) -o $@
+ $(Q)gcc $(CPARSEROS_E) $(LINKFLAGS) -o $@
cparser.bootstrap2: cparser.bootstrap $(CPARSEROS2)
@echo "===> LD $@"
- $(Q)./cparser.bootstrap $(CPARSEROS2) $(LFLAGS) -o $@
+ $(Q)./cparser.bootstrap $(CPARSEROS2) $(LINKFLAGS) -o $@
-$(BUILDDIR)/%.o: %.c
- @echo '===> CC $<'
- $(Q)$(CC) $(CPPFLAGS) $(CFLAGS) -MMD -c $< -o $@
+$(builddir)/%.o: %.c
+ @echo '===> CC $@'
+ $(Q)$(CC) $(CPPFLAGS) $(CFLAGS) -MMD -c -o $@ $<
clean:
@echo '===> CLEAN'
- $(Q)rm -rf $(OBJECTS) $(GOAL)
+ $(Q)rm -rf $(cparser_OBJECTS) $(GOAL)
diff --git a/adt/error.h b/adt/error.h
index ad6c08d..49a3a8c 100644
--- a/adt/error.h
+++ b/adt/error.h
@@ -24,8 +24,12 @@
#include <stdlib.h>
#include "config.h"
-static inline __attribute__((noreturn))
-void panic(const char *msg)
-{ fprintf(stderr, "Panic: %s\n", msg); abort(); }
+static inline __attribute__((noreturn)) void panic(char const *const file, int const line, char const *const func, char const *const msg)
+{
+ fprintf(stderr, "%s:%d: panic in %s: %s\n", file, line, func, msg);
+ abort();
+}
+
+#define panic(msg) panic(__FILE__, __LINE__, __func__, (msg))
#endif
diff --git a/ast.c b/ast.c
index 063ac47..da758db 100644
--- a/ast.c
+++ b/ast.c
@@ -26,6 +26,7 @@
#include "lang_features.h"
#include "entity_t.h"
#include "printer.h"
+#include "separator_t.h"
#include "types.h"
#include <assert.h>
@@ -288,10 +289,9 @@ static void print_call_expression(const call_expression_t *call)
{
print_expression_prec(call->function, PREC_POSTFIX);
print_char('(');
- char const *sep = "";
+ separator_t sep = { "", ", " };
for (call_argument_t const *arg = call->arguments; arg; arg = arg->next) {
- print_string(sep);
- sep = ", ";
+ print_string(sep_next(&sep));
print_assignment_expression(arg->expression);
}
print_char(')');
@@ -1005,19 +1005,17 @@ static void print_for_statement(const for_statement_t *statement)
*
* @param arguments the arguments
*/
-static void print_asm_arguments(asm_argument_t *arguments)
-{
- asm_argument_t *argument = arguments;
- for (; argument != NULL; argument = argument->next) {
- if (argument != arguments)
- print_string(", ");
-
- if (argument->symbol) {
- print_format("[%s] ", argument->symbol->string);
- }
- print_quoted_string(&argument->constraints, '"');
+static void print_asm_arguments(asm_argument_t const *const arguments)
+{
+ print_string(" :");
+ separator_t sep = { " ", ", " };
+ for (asm_argument_t const *i = arguments; i; i = i->next) {
+ print_string(sep_next(&sep));
+ if (i->symbol)
+ print_format("[%s] ", i->symbol->string);
+ print_quoted_string(&i->constraints, '"');
print_string(" (");
- print_expression(argument->expression);
+ print_expression(i->expression);
print_char(')');
}
}
@@ -1027,49 +1025,50 @@ static void print_asm_arguments(asm_argument_t *arguments)
*
* @param clobbers the clobbers
*/
-static void print_asm_clobbers(asm_clobber_t *clobbers)
+static void print_asm_clobbers(asm_clobber_t const *const clobbers)
{
- asm_clobber_t *clobber = clobbers;
- for (; clobber != NULL; clobber = clobber->next) {
- if (clobber != clobbers)
- print_string(", ");
+ print_string(" :");
+ separator_t sep = { " ", ", " };
+ for (asm_clobber_t const *i = clobbers; i; i = i->next) {
+ print_string(sep_next(&sep));
+ print_quoted_string(&i->clobber, '"');
+ }
+}
- print_quoted_string(&clobber->clobber, '"');
+static void print_asm_labels(asm_label_t const *const labels)
+{
+ print_string(" :");
+ separator_t sep = { " ", ", " };
+ for (asm_label_t const *i = labels; i; i = i->next) {
+ print_string(sep_next(&sep));
+ print_string(i->label->base.symbol->string);
}
}
/**
* Print an assembler statement.
*
- * @param statement the statement
+ * @param stmt the statement
*/
-static void print_asm_statement(const asm_statement_t *statement)
+static void print_asm_statement(asm_statement_t const *const stmt)
{
- print_string("asm ");
- if (statement->is_volatile) {
- print_string("volatile ");
- }
+ print_string("asm");
+ if (stmt->is_volatile) print_string(" volatile");
+ if (stmt->labels) print_string(" goto");
print_char('(');
- print_quoted_string(&statement->asm_text, '"');
- if (statement->outputs == NULL &&
- statement->inputs == NULL &&
- statement->clobbers == NULL)
- goto end_of_print_asm_statement;
-
- print_string(" : ");
- print_asm_arguments(statement->outputs);
- if (statement->inputs == NULL && statement->clobbers == NULL)
- goto end_of_print_asm_statement;
-
- print_string(" : ");
- print_asm_arguments(statement->inputs);
- if (statement->clobbers == NULL)
- goto end_of_print_asm_statement;
-
- print_string(" : ");
- print_asm_clobbers(statement->clobbers);
-
-end_of_print_asm_statement:
+ print_quoted_string(&stmt->asm_text, '"');
+
+ unsigned const n =
+ stmt->labels ? 4 :
+ stmt->clobbers ? 3 :
+ stmt->inputs ? 2 :
+ stmt->outputs ? 1 :
+ 0;
+ if (n >= 1) print_asm_arguments(stmt->outputs);
+ if (n >= 2) print_asm_arguments(stmt->inputs);
+ if (n >= 3) print_asm_clobbers( stmt->clobbers);
+ if (n >= 4) print_asm_labels( stmt->labels);
+
print_string(");");
}
@@ -1206,26 +1205,20 @@ static void print_ms_modifiers(const declaration_t *declaration)
decl_modifiers_t modifiers = declaration->modifiers;
- bool ds_shown = false;
- const char *next = "(";
+ separator_t sep = { "__declspec(", ", " };
if (declaration->base.kind == ENTITY_VARIABLE) {
variable_t *variable = (variable_t*)declaration;
if (variable->alignment != 0
|| variable->get_property_sym != NULL
|| variable->put_property_sym != NULL) {
- if (!ds_shown) {
- print_string("__declspec");
- ds_shown = true;
- }
-
if (variable->alignment != 0) {
- print_string(next); next = ", "; print_format("align(%u)", variable->alignment);
+ print_format("%salign(%u)", sep_next(&sep), variable->alignment);
}
if (variable->get_property_sym != NULL
|| variable->put_property_sym != NULL) {
char *comma = "";
- print_string(next); next = ", "; print_string("property(");
+ print_format("%sproperty(", sep_next(&sep));
if (variable->get_property_sym != NULL) {
print_format("get=%s", variable->get_property_sym->string);
comma = ", ";
@@ -1239,52 +1232,48 @@ static void print_ms_modifiers(const declaration_t *declaration)
/* DM_FORCEINLINE handled outside. */
if ((modifiers & ~DM_FORCEINLINE) != 0) {
- if (!ds_shown) {
- print_string("__declspec");
- ds_shown = true;
- }
if (modifiers & DM_DLLIMPORT) {
- print_string(next); next = ", "; print_string("dllimport");
+ print_format("%sdllimport", sep_next(&sep));
}
if (modifiers & DM_DLLEXPORT) {
- print_string(next); next = ", "; print_string("dllexport");
+ print_format("%sdllexport", sep_next(&sep));
}
if (modifiers & DM_THREAD) {
- print_string(next); next = ", "; print_string("thread");
+ print_format("%sthread", sep_next(&sep));
}
if (modifiers & DM_NAKED) {
- print_string(next); next = ", "; print_string("naked");
+ print_format("%snaked", sep_next(&sep));
}
if (modifiers & DM_THREAD) {
- print_string(next); next = ", "; print_string("thread");
+ print_format("%sthread", sep_next(&sep));
}
if (modifiers & DM_SELECTANY) {
- print_string(next); next = ", "; print_string("selectany");
+ print_format("%sselectany", sep_next(&sep));
}
if (modifiers & DM_NOTHROW) {
- print_string(next); next = ", "; print_string("nothrow");
+ print_format("%snothrow", sep_next(&sep));
}
if (modifiers & DM_NORETURN) {
- print_string(next); next = ", "; print_string("noreturn");
+ print_format("%snoreturn", sep_next(&sep));
}
if (modifiers & DM_NOINLINE) {
- print_string(next); next = ", "; print_string("noinline");
+ print_format("%snoinline", sep_next(&sep));
}
if (modifiers & DM_DEPRECATED) {
- print_string(next); next = ", "; print_string("deprecated");
+ print_format("%sdeprecated", sep_next(&sep));
if (declaration->deprecated_string != NULL)
print_format("(\"%s\")",
declaration->deprecated_string);
}
if (modifiers & DM_RESTRICT) {
- print_string(next); next = ", "; print_string("restrict");
+ print_format("%srestrict", sep_next(&sep));
}
if (modifiers & DM_NOALIAS) {
- print_string(next); next = ", "; print_string("noalias");
+ print_format("%snoalias", sep_next(&sep));
}
}
- if (ds_shown)
+ if (!sep_at_first(&sep))
print_string(") ");
}
#endif
@@ -1344,9 +1333,9 @@ void print_declaration(const entity_t *entity)
print_type_ext(entity->declaration.type, entity->base.symbol,
&entity->function.parameters);
- if (entity->function.statement != NULL) {
+ if (entity->function.body != NULL) {
print_char('\n');
- print_indented_statement(entity->function.statement);
+ print_indented_statement(entity->function.body);
print_char('\n');
return;
}
@@ -1918,7 +1907,7 @@ check_type:
case EXPR_ERROR:
return EXPR_CLASS_ERROR;
}
- panic("invalid expression found (is constant expression)");
+ panic("invalid expression");
}
void init_ast(void)
diff --git a/ast.h b/ast.h
index b691f09..f7c0ce4 100644
--- a/ast.h
+++ b/ast.h
@@ -30,7 +30,6 @@ typedef struct string_literal_expression_t string_literal_expression_t
typedef struct funcname_expression_t funcname_expression_t;
typedef struct compound_literal_expression_t compound_literal_expression_t;
typedef struct reference_expression_t reference_expression_t;
-typedef struct cast_expression_t cast_expression_t;
typedef struct call_argument_t call_argument_t;
typedef struct call_expression_t call_expression_t;
typedef struct binary_expression_t binary_expression_t;
@@ -39,8 +38,6 @@ typedef struct select_expression_t select_expression_t;
typedef struct array_access_expression_t array_access_expression_t;
typedef struct typeprop_expression_t typeprop_expression_t;
typedef struct conditional_expression_t conditional_expression_t;
-typedef struct expression_list_element_t expression_list_element_t;
-typedef struct comma_expression_t comma_expression_t;
typedef struct statement_expression_t statement_expression_t;
typedef struct designator_t designator_t;
typedef struct offsetof_expression_t offsetof_expression_t;
@@ -60,8 +57,6 @@ typedef struct initializer_designator_t initializer_designator_t;
typedef union initializer_t initializer_t;
typedef struct statement_base_t statement_base_t;
-typedef struct invalid_statement_t invalid_statement_t;
-typedef struct empty_statement_t empty_statement_t;
typedef struct compound_statement_t compound_statement_t;
typedef struct return_statement_t return_statement_t;
typedef struct if_statement_t if_statement_t;
@@ -76,6 +71,7 @@ typedef struct do_while_statement_t do_while_statement_t;
typedef struct for_statement_t for_statement_t;
typedef struct asm_argument_t asm_argument_t;
typedef struct asm_clobber_t asm_clobber_t;
+typedef struct asm_label_t asm_label_t;
typedef struct asm_statement_t asm_statement_t;
typedef struct ms_try_statement_t ms_try_statement_t;
typedef struct leave_statement_t leave_statement_t;
diff --git a/ast2firm.c b/ast2firm.c
index 226eebe..b425a1e 100644
--- a/ast2firm.c
+++ b/ast2firm.c
@@ -35,6 +35,7 @@
#include "adt/array.h"
#include "adt/strutil.h"
#include "adt/util.h"
+#include "jump_target.h"
#include "symbol_t.h"
#include "token_t.h"
#include "type_t.h"
@@ -63,7 +64,6 @@ fp_model_t firm_fp_model = fp_model_precise;
static const backend_params *be_params;
static ir_type *ir_type_char;
-static ir_type *ir_type_wchar_t;
/* architecture specific floating point arithmetic mode (if any) */
static ir_mode *mode_float_arithmetic;
@@ -71,15 +71,36 @@ static ir_mode *mode_float_arithmetic;
/* alignment of stack parameters */
static unsigned stack_param_align;
-static int next_value_number_function;
-static ir_node *continue_label;
-static ir_node *break_label;
-static ir_node *current_switch;
-static bool saw_default_label;
-static label_t **all_labels;
-static entity_t **inner_functions;
-static ir_node *ijmp_list;
-static bool constant_folding;
+static int next_value_number_function;
+static jump_target continue_target;
+static jump_target break_target;
+static ir_node *current_switch;
+static bool saw_default_label;
+static entity_t **inner_functions;
+static jump_target ijmp_target;
+static ir_node **ijmp_ops;
+static ir_node **ijmp_blocks;
+static bool constant_folding;
+
+#define PUSH_BREAK(val) \
+ jump_target const old_break_target = break_target; \
+ (init_jump_target(&break_target, (val)))
+#define POP_BREAK() \
+ ((void)(break_target = old_break_target))
+
+#define PUSH_CONTINUE(val) \
+ jump_target const old_continue_target = continue_target; \
+ (init_jump_target(&continue_target, (val)))
+#define POP_CONTINUE() \
+ ((void)(continue_target = old_continue_target))
+
+#define PUSH_IRG(val) \
+ ir_graph *const old_irg = current_ir_graph; \
+ ir_graph *const new_irg = (val); \
+ ((void)(current_ir_graph = new_irg))
+
+#define POP_IRG() \
+ (assert(current_ir_graph == new_irg), (void)(current_ir_graph = old_irg))
static const entity_t *current_function_entity;
static ir_node *current_function_name;
@@ -605,9 +626,7 @@ static ir_type *create_compound_type(compound_type_t *const type, bool const inc
return irtype;
}
-static ir_tarval *fold_constant_to_tarval(expression_t const *);
-
-static void determine_enum_values(enum_type_t *const type)
+void determine_enum_values(enum_type_t *const type)
{
ir_mode *const mode = atomic_modes[type->base.akind];
ir_tarval *const one = get_mode_one(mode);
@@ -852,7 +871,7 @@ static bool declaration_is_definition(const entity_t *entity)
case ENTITY_VARIABLE:
return entity->declaration.storage_class != STORAGE_CLASS_EXTERN;
case ENTITY_FUNCTION:
- return entity->function.statement != NULL;
+ return entity->function.body != NULL;
case ENTITY_PARAMETER:
case ENTITY_COMPOUND_MEMBER:
return false;
@@ -864,7 +883,7 @@ static bool declaration_is_definition(const entity_t *entity)
case ENTITY_LOCAL_LABEL:
break;
}
- panic("declaration_is_definition called on non-declaration");
+ panic("entity is not a declaration");
}
/**
@@ -879,12 +898,19 @@ static void handle_decl_modifiers(ir_entity *irentity, entity_t *entity)
decl_modifiers_t modifiers = entity->declaration.modifiers;
if (is_method_entity(irentity)) {
- if (modifiers & DM_PURE) {
- set_entity_additional_properties(irentity, mtp_property_pure);
- }
- if (modifiers & DM_CONST) {
+ if (modifiers & DM_PURE)
+ add_entity_additional_properties(irentity, mtp_property_pure);
+ if (modifiers & DM_CONST)
add_entity_additional_properties(irentity, mtp_property_const);
- }
+ if (modifiers & DM_NOINLINE)
+ add_entity_additional_properties(irentity, mtp_property_noinline);
+ if (modifiers & DM_FORCEINLINE)
+ add_entity_additional_properties(irentity, mtp_property_always_inline);
+ if (modifiers & DM_NAKED)
+ add_entity_additional_properties(irentity, mtp_property_naked);
+ if (entity->kind == ENTITY_FUNCTION && entity->function.is_inline)
+ add_entity_additional_properties(irentity,
+ mtp_property_inline_recommended);
}
if ((modifiers & DM_USED) && declaration_is_definition(entity)) {
add_entity_linkage(irentity, IR_LINKAGE_HIDDEN_USER);
@@ -938,7 +964,7 @@ static ir_entity *get_function_entity(entity_t *entity, ir_type *owner_type)
/* already an entity defined? */
ir_entity *irentity = entitymap_get(&entitymap, symbol);
- bool const has_body = entity->function.statement != NULL;
+ bool const has_body = entity->function.body != NULL;
if (irentity != NULL) {
goto entity_created;
}
@@ -1107,7 +1133,8 @@ static ir_node *string_to_firm(source_position_t const *const src_pos, char cons
ir_initializer_t *const initializer = create_initializer_compound(slen);
ir_type * elem_type;
switch (value->encoding) {
- case STRING_ENCODING_CHAR: {
+ case STRING_ENCODING_CHAR:
+ case STRING_ENCODING_UTF8: {
elem_type = ir_type_char;
ir_mode *const mode = get_type_mode(elem_type);
@@ -1120,8 +1147,13 @@ static ir_node *string_to_firm(source_position_t const *const src_pos, char cons
goto finish;
}
- case STRING_ENCODING_WIDE: {
- elem_type = ir_type_wchar_t;
+ {
+ type_t *type;
+ case STRING_ENCODING_CHAR16: type = type_char16_t; goto init_wide;
+ case STRING_ENCODING_CHAR32: type = type_char32_t; goto init_wide;
+ case STRING_ENCODING_WIDE: type = type_wchar_t; goto init_wide;
+init_wide:;
+ elem_type = get_ir_type(type);
ir_mode *const mode = get_type_mode(elem_type);
char const *p = value->begin;
@@ -1243,7 +1275,7 @@ static ir_node *literal_to_firm(const literal_expression_t *literal)
break;
default:
- panic("Invalid literal kind found");
+ panic("invalid literal kind");
}
dbg_info *dbgi = get_dbg_info(&literal->base.source_position);
@@ -1293,7 +1325,7 @@ static ir_node *char_literal_to_firm(string_literal_expression_t const *literal)
}
default:
- panic("Invalid literal kind found");
+ panic("invalid literal kind");
}
dbg_info *dbgi = get_dbg_info(&literal->base.source_position);
@@ -1436,16 +1468,13 @@ static ir_node *get_local_frame(ir_entity *const ent)
}
/**
- * Keep all memory edges of the given block.
+ * Keep the current block and memory.
+ * This is necessary for all loops, because they could become infinite.
*/
-static void keep_all_memory(ir_node *block)
+static void keep_loop(void)
{
- ir_node *old = get_cur_block();
-
- set_cur_block(block);
+ keep_alive(get_cur_block());
keep_alive(get_store());
- /* TODO: keep all memory edges from restricted pointers */
- set_cur_block(old);
}
static ir_node *enum_constant_to_firm(reference_expression_t const *const ref)
@@ -1527,7 +1556,7 @@ static ir_node *reference_addr(const reference_expression_t *ref)
panic("not implemented reference type");
}
- panic("reference to declaration with unknown type found");
+ panic("reference to declaration with unknown type");
}
static ir_node *reference_expression_to_firm(const reference_expression_t *ref)
@@ -1641,7 +1670,7 @@ static ir_node *process_builtin_call(const call_expression_t *call)
case BUILTIN_LIBC_CHECK:
panic("builtin did not produce an entity");
}
- panic("invalid builtin found");
+ panic("invalid builtin");
}
/**
@@ -1796,9 +1825,7 @@ static ir_node *statement_to_firm(statement_t *statement);
static ir_node *compound_statement_to_firm(compound_statement_t *compound);
static ir_node *expression_to_addr(const expression_t *expression);
-static ir_node *create_condition_evaluation(const expression_t *expression,
- ir_node *true_block,
- ir_node *false_block);
+static ir_node *create_condition_evaluation(expression_t const *expression, jump_target *true_target, jump_target *false_target);
static void assign_value(dbg_info *dbgi, ir_node *addr, type_t *type,
ir_node *value)
@@ -2093,7 +2120,7 @@ static ir_node *create_incdec(const unary_expression_t *expression)
store_value = result;
break;
default:
- panic("no incdec expr in create_incdec");
+ panic("no incdec expr");
}
set_value_for_expression_addr(value_expr, store_value, addr);
@@ -2325,7 +2352,7 @@ static ir_node *unary_expression_to_firm(const unary_expression_t *expression)
default:
break;
}
- panic("invalid UNEXPR type found");
+ panic("invalid unary expression type");
}
/**
@@ -2334,23 +2361,36 @@ static ir_node *unary_expression_to_firm(const unary_expression_t *expression)
static ir_node *produce_condition_result(const expression_t *expression,
ir_mode *mode, dbg_info *dbgi)
{
- ir_node *const one_block = new_immBlock();
- ir_node *const zero_block = new_immBlock();
- create_condition_evaluation(expression, one_block, zero_block);
- mature_immBlock(one_block);
- mature_immBlock(zero_block);
+ jump_target true_target;
+ jump_target false_target;
+ init_jump_target(&true_target, NULL);
+ init_jump_target(&false_target, NULL);
+ create_condition_evaluation(expression, &true_target, &false_target);
- ir_node *const jmp_one = new_rd_Jmp(dbgi, one_block);
- ir_node *const jmp_zero = new_rd_Jmp(dbgi, zero_block);
- ir_node *const in_cf[2] = { jmp_one, jmp_zero };
- ir_node *const block = new_Block(lengthof(in_cf), in_cf);
- set_cur_block(block);
+ ir_node *val = NULL;
+ jump_target exit_target;
+ init_jump_target(&exit_target, NULL);
+
+ if (enter_jump_target(&true_target)) {
+ val = new_Const(get_mode_one(mode));
+ jump_to_target(&exit_target);
+ }
- ir_node *const one = new_Const(get_mode_one(mode));
- ir_node *const zero = new_Const(get_mode_null(mode));
- ir_node *const in[2] = { one, zero };
- ir_node *const val = new_d_Phi(dbgi, lengthof(in), in, mode);
+ if (enter_jump_target(&false_target)) {
+ ir_node *const zero = new_Const(get_mode_null(mode));
+ jump_to_target(&exit_target);
+ if (val) {
+ ir_node *const in[] = { val, zero };
+ val = new_rd_Phi(dbgi, exit_target.block, lengthof(in), in, mode);
+ } else {
+ val = zero;
+ }
+ }
+ if (!enter_jump_target(&exit_target)) {
+ set_cur_block(new_Block(0, NULL));
+ val = new_Unknown(mode);
+ }
return val;
}
@@ -2698,13 +2738,9 @@ static ir_entity *create_initializer_entity(dbg_info *dbgi,
type_t *type)
{
/* create the ir_initializer */
- ir_graph *const old_current_ir_graph = current_ir_graph;
- current_ir_graph = get_const_code_irg();
-
+ PUSH_IRG(get_const_code_irg());
ir_initializer_t *irinitializer = create_ir_initializer(initializer, type);
-
- assert(current_ir_graph == get_const_code_irg());
- current_ir_graph = old_current_ir_graph;
+ POP_IRG();
ident *const id = id_unique("initializer.%u");
ir_type *const irtype = get_ir_type(type);
@@ -2820,7 +2856,7 @@ static ir_node *alignof_to_firm(const typeprop_expression_t *expression)
static void init_ir_types(void);
-static ir_tarval *fold_constant_to_tarval(const expression_t *expression)
+ir_tarval *fold_constant_to_tarval(const expression_t *expression)
{
assert(is_constant_expression(expression) == EXPR_CLASS_CONSTANT);
@@ -2833,12 +2869,10 @@ static ir_tarval *fold_constant_to_tarval(const expression_t *expression)
init_ir_types();
- ir_graph *old_current_ir_graph = current_ir_graph;
- current_ir_graph = get_const_code_irg();
-
+ PUSH_IRG(get_const_code_irg());
ir_node *const cnst = _expression_to_firm(expression);
+ POP_IRG();
- current_ir_graph = old_current_ir_graph;
set_optimize(old_optimize);
set_opt_constant_folding(old_constant_folding);
@@ -2878,8 +2912,6 @@ bool fold_constant_to_bool(const expression_t *expression)
static ir_node *conditional_to_firm(const conditional_expression_t *expression)
{
- dbg_info *const dbgi = get_dbg_info(&expression->base.source_position);
-
/* first try to fold a constant condition */
if (is_constant_expression(expression->condition) == EXPR_CLASS_CONSTANT) {
bool val = fold_constant_to_bool(expression->condition);
@@ -2893,43 +2925,47 @@ static ir_node *conditional_to_firm(const conditional_expression_t *expression)
}
}
- ir_node *const true_block = new_immBlock();
- ir_node *const false_block = new_immBlock();
- ir_node *const cond_expr = create_condition_evaluation(expression->condition, true_block, false_block);
- mature_immBlock(true_block);
- mature_immBlock(false_block);
-
- set_cur_block(true_block);
- ir_node *true_val;
- if (expression->true_expression != NULL) {
- true_val = expression_to_firm(expression->true_expression);
- } else if (cond_expr != NULL && get_irn_mode(cond_expr) != mode_b) {
- true_val = cond_expr;
- } else {
- /* Condition ended with a short circuit (&&, ||, !) operation or a
- * comparison. Generate a "1" as value for the true branch. */
- true_val = new_Const(get_mode_one(mode_Is));
- }
- ir_node *const true_jmp = new_d_Jmp(dbgi);
-
- set_cur_block(false_block);
- ir_node *const false_val = expression_to_firm(expression->false_expression);
- ir_node *const false_jmp = new_d_Jmp(dbgi);
+ jump_target true_target;
+ jump_target false_target;
+ init_jump_target(&true_target, NULL);
+ init_jump_target(&false_target, NULL);
+ ir_node *const cond_expr = create_condition_evaluation(expression->condition, &true_target, &false_target);
- /* create the common block */
- ir_node *const in_cf[2] = { true_jmp, false_jmp };
- ir_node *const block = new_Block(lengthof(in_cf), in_cf);
- set_cur_block(block);
+ ir_node *val = NULL;
+ jump_target exit_target;
+ init_jump_target(&exit_target, NULL);
- /* TODO improve static semantics, so either both or no values are NULL */
- if (true_val == NULL || false_val == NULL)
- return NULL;
+ if (enter_jump_target(&true_target)) {
+ if (expression->true_expression) {
+ val = expression_to_firm(expression->true_expression);
+ } else if (cond_expr && get_irn_mode(cond_expr) != mode_b) {
+ val = cond_expr;
+ } else {
+ /* Condition ended with a short circuit (&&, ||, !) operation or a
+ * comparison. Generate a "1" as value for the true branch. */
+ val = new_Const(get_mode_one(mode_Is));
+ }
+ jump_to_target(&exit_target);
+ }
- ir_node *const in[2] = { true_val, false_val };
- type_t *const type = skip_typeref(expression->base.type);
- ir_mode *const mode = get_ir_mode_arithmetic(type);
- ir_node *const val = new_d_Phi(dbgi, lengthof(in), in, mode);
+ if (enter_jump_target(&false_target)) {
+ ir_node *const false_val = expression_to_firm(expression->false_expression);
+ jump_to_target(&exit_target);
+ if (val) {
+ ir_node *const in[] = { val, false_val };
+ dbg_info *const dbgi = get_dbg_info(&expression->base.source_position);
+ val = new_rd_Phi(dbgi, exit_target.block, lengthof(in), in, get_irn_mode(val));
+ } else {
+ val = false_val;
+ }
+ }
+ if (!enter_jump_target(&exit_target)) {
+ set_cur_block(new_Block(0, NULL));
+ type_t *const type = skip_typeref(expression->base.type);
+ if (!is_type_void(type))
+ val = new_Unknown(get_ir_mode_arithmetic(type));
+ }
return val;
}
@@ -3043,7 +3079,7 @@ static ir_node *classify_type_to_firm(const classify_type_expression_t *const ex
tc = real_type_class;
goto make_const;
}
- panic("Unexpected atomic type in classify_type_to_firm().");
+ panic("Unexpected atomic type.");
}
case TYPE_COMPLEX: tc = complex_type_class; goto make_const;
@@ -3066,7 +3102,7 @@ static ir_node *classify_type_to_firm(const classify_type_expression_t *const ex
case TYPE_ERROR:
break;
}
- panic("unexpected TYPE classify_type_to_firm().");
+ panic("unexpected type.");
}
make_const:;
@@ -3213,24 +3249,14 @@ static ir_node *builtin_types_compatible_to_firm(
return create_Const_from_bool(mode, value);
}
-static ir_node *get_label_block(label_t *label)
+static void prepare_label_target(label_t *const label)
{
- if (label->block != NULL)
- return label->block;
-
- /* beware: might be called from create initializer with current_ir_graph
- * set to const_code_irg. */
- ir_graph *rem = current_ir_graph;
- current_ir_graph = current_function;
-
- ir_node *block = new_immBlock();
-
- label->block = block;
-
- ARR_APP1(label_t *, all_labels, label);
-
- current_ir_graph = rem;
- return block;
+ if (label->address_taken && !label->indirect_block) {
+ ir_node *const iblock = new_immBlock();
+ label->indirect_block = iblock;
+ ARR_APP1(ir_node*, ijmp_blocks, iblock);
+ jump_from_block_to_target(&label->target, iblock);
+ }
}
/**
@@ -3239,12 +3265,15 @@ static ir_node *get_label_block(label_t *label)
*/
static ir_node *label_address_to_firm(const label_address_expression_t *label)
{
- dbg_info *dbgi = get_dbg_info(&label->base.source_position);
- ir_node *block = get_label_block(label->label);
- ir_entity *entity = create_Block_entity(block);
+ /* Beware: Might be called from create initializer with current_ir_graph
+ * set to const_code_irg. */
+ PUSH_IRG(current_function);
+ prepare_label_target(label->label);
+ POP_IRG();
symconst_symbol value;
- value.entity_p = entity;
+ value.entity_p = create_Block_entity(label->label->indirect_block);
+ dbg_info *const dbgi = get_dbg_info(&label->base.source_position);
return new_d_SymConst(dbgi, mode_P_code, value, symconst_addr_ent);
}
@@ -3291,7 +3320,7 @@ static ir_node *_expression_to_firm(expression_t const *const expr)
case EXPR_ERROR: break;
}
- panic("invalid expression found");
+ panic("invalid expression");
}
/**
@@ -3367,65 +3396,61 @@ static ir_node *expression_to_firm(const expression_t *expression)
* create a short-circuit expression evaluation that tries to construct
* efficient control flow structures for &&, || and ! expressions
*/
-static ir_node *create_condition_evaluation(const expression_t *expression,
- ir_node *true_block,
- ir_node *false_block)
+static ir_node *create_condition_evaluation(expression_t const *const expression, jump_target *const true_target, jump_target *const false_target)
{
switch(expression->kind) {
case EXPR_UNARY_NOT: {
const unary_expression_t *unary_expression = &expression->unary;
- create_condition_evaluation(unary_expression->value, false_block,
- true_block);
+ create_condition_evaluation(unary_expression->value, false_target, true_target);
return NULL;
}
case EXPR_BINARY_LOGICAL_AND: {
- const binary_expression_t *binary_expression = &expression->binary;
-
- ir_node *extra_block = new_immBlock();
- create_condition_evaluation(binary_expression->left, extra_block,
- false_block);
- mature_immBlock(extra_block);
- set_cur_block(extra_block);
- create_condition_evaluation(binary_expression->right, true_block,
- false_block);
+ jump_target extra_target;
+ init_jump_target(&extra_target, NULL);
+ create_condition_evaluation(expression->binary.left, &extra_target, false_target);
+ if (enter_jump_target(&extra_target))
+ create_condition_evaluation(expression->binary.right, true_target, false_target);
return NULL;
}
case EXPR_BINARY_LOGICAL_OR: {
- const binary_expression_t *binary_expression = &expression->binary;
-
- ir_node *extra_block = new_immBlock();
- create_condition_evaluation(binary_expression->left, true_block,
- extra_block);
- mature_immBlock(extra_block);
- set_cur_block(extra_block);
- create_condition_evaluation(binary_expression->right, true_block,
- false_block);
+ jump_target extra_target;
+ init_jump_target(&extra_target, NULL);
+ create_condition_evaluation(expression->binary.left, true_target, &extra_target);
+ if (enter_jump_target(&extra_target))
+ create_condition_evaluation(expression->binary.right, true_target, false_target);
return NULL;
}
default:
break;
}
- dbg_info *dbgi = get_dbg_info(&expression->base.source_position);
- ir_node *cond_expr = _expression_to_firm(expression);
- ir_node *condition = create_conv(dbgi, cond_expr, mode_b);
- ir_node *cond = new_d_Cond(dbgi, condition);
- ir_node *true_proj = new_d_Proj(dbgi, cond, mode_X, pn_Cond_true);
- ir_node *false_proj = new_d_Proj(dbgi, cond, mode_X, pn_Cond_false);
-
- /* set branch prediction info based on __builtin_expect */
- if (is_builtin_expect(expression) && is_Cond(cond)) {
- call_argument_t *argument = expression->call.arguments->next;
- if (is_constant_expression(argument->expression) == EXPR_CLASS_CONSTANT) {
- bool const cnst = fold_constant_to_bool(argument->expression);
- cond_jmp_predicate const pred = cnst ? COND_JMP_PRED_TRUE : COND_JMP_PRED_FALSE;
- set_Cond_jmp_pred(cond, pred);
+ ir_node *cond_expr = _expression_to_firm(expression);
+ if (is_Const(cond_expr)) {
+ if (tarval_is_null(get_Const_tarval(cond_expr))) {
+ jump_to_target(false_target);
+ } else {
+ jump_to_target(true_target);
+ }
+ } else {
+ dbg_info *dbgi = get_dbg_info(&expression->base.source_position);
+ ir_node *condition = create_conv(dbgi, cond_expr, mode_b);
+ ir_node *cond = new_d_Cond(dbgi, condition);
+ ir_node *true_proj = new_d_Proj(dbgi, cond, mode_X, pn_Cond_true);
+ ir_node *false_proj = new_d_Proj(dbgi, cond, mode_X, pn_Cond_false);
+
+ /* set branch prediction info based on __builtin_expect */
+ if (is_builtin_expect(expression) && is_Cond(cond)) {
+ call_argument_t *argument = expression->call.arguments->next;
+ if (is_constant_expression(argument->expression) == EXPR_CLASS_CONSTANT) {
+ bool const cnst = fold_constant_to_bool(argument->expression);
+ cond_jmp_predicate const pred = cnst ? COND_JMP_PRED_TRUE : COND_JMP_PRED_FALSE;
+ set_Cond_jmp_pred(cond, pred);
+ }
}
- }
-
- add_immBlock_pred(true_block, true_proj);
- add_immBlock_pred(false_block, false_proj);
+ add_pred_to_jump_target(true_target, true_proj);
+ add_pred_to_jump_target(false_target, false_proj);
+ }
set_unreachable_now();
return cond_expr;
}
@@ -3667,7 +3692,7 @@ static void advance_current_object(type_path_t *path)
{
if (path->invalid) {
/* TODO: handle this... */
- panic("invalid initializer in ast2firm (excessive elements)");
+ panic("invalid initializer (excessive elements)");
}
type_path_entry_t *top = get_type_path_top(path);
@@ -3809,6 +3834,7 @@ static ir_initializer_t *create_ir_initializer_string(initializer_t const *const
char const * p = str->value.begin;
switch (str->value.encoding) {
case STRING_ENCODING_CHAR:
+ case STRING_ENCODING_UTF8:
for (size_t i = 0; i != arr_len; ++i) {
char const c = i < str_len ? *p++ : 0;
ir_tarval *const tv = new_tarval_from_long(c, mode);
@@ -3817,6 +3843,8 @@ static ir_initializer_t *create_ir_initializer_string(initializer_t const *const
}
break;
+ case STRING_ENCODING_CHAR16:
+ case STRING_ENCODING_CHAR32:
case STRING_ENCODING_WIDE:
for (size_t i = 0; i != arr_len; ++i) {
utf32 const c = i < str_len ? read_utf8_char(&p) : 0;
@@ -3844,7 +3872,7 @@ static ir_initializer_t *create_ir_initializer(
return create_ir_initializer_value(&initializer->value);
case INITIALIZER_DESIGNATOR:
- panic("unexpected designator initializer found");
+ panic("unexpected designator initializer");
}
panic("unknown initializer");
}
@@ -3993,7 +4021,7 @@ static void create_dynamic_initializer_sub(ir_initializer_t *initializer,
}
}
- panic("invalid IR_INITIALIZER found");
+ panic("invalid ir_initializer");
}
static void create_dynamic_initializer(ir_initializer_t *initializer,
@@ -4155,6 +4183,14 @@ static void allocate_variable_length_array(entity_t *entity)
entity->variable.v.vla_base = addr;
}
+static bool var_needs_entity(variable_t const *const var)
+{
+ if (var->address_taken)
+ return true;
+ type_t *const type = skip_typeref(var->base.type);
+ return !is_type_scalar(type) || type->base.qualifiers & TYPE_QUALIFIER_VOLATILE;
+}
+
/**
* Creates a Firm local variable from a declaration.
*/
@@ -4163,31 +4199,23 @@ static void create_local_variable(entity_t *entity)
assert(entity->kind == ENTITY_VARIABLE);
assert(entity->declaration.kind == DECLARATION_KIND_UNKNOWN);
- bool needs_entity = entity->variable.address_taken;
- type_t *type = skip_typeref(entity->declaration.type);
+ if (!var_needs_entity(&entity->variable)) {
+ entity->declaration.kind = DECLARATION_KIND_LOCAL_VARIABLE;
+ entity->variable.v.value_number = next_value_number_function;
+ set_irg_loc_description(current_ir_graph, next_value_number_function, entity);
+ ++next_value_number_function;
+ return;
+ }
/* is it a variable length array? */
+ type_t *const type = skip_typeref(entity->declaration.type);
if (is_type_array(type) && !type->array.size_constant) {
create_variable_length_array(entity);
return;
- } else if (is_type_array(type) || is_type_compound(type)) {
- needs_entity = true;
- } else if (type->base.qualifiers & TYPE_QUALIFIER_VOLATILE) {
- needs_entity = true;
}
- if (needs_entity) {
- ir_type *frame_type = get_irg_frame_type(current_ir_graph);
- create_variable_entity(entity,
- DECLARATION_KIND_LOCAL_VARIABLE_ENTITY,
- frame_type);
- } else {
- entity->declaration.kind = DECLARATION_KIND_LOCAL_VARIABLE;
- entity->variable.v.value_number = next_value_number_function;
- set_irg_loc_description(current_ir_graph, next_value_number_function,
- entity);
- ++next_value_number_function;
- }
+ ir_type *const frame_type = get_irg_frame_type(current_ir_graph);
+ create_variable_entity(entity, DECLARATION_KIND_LOCAL_VARIABLE_ENTITY, frame_type);
}
static void create_local_static_variable(entity_t *entity)
@@ -4222,13 +4250,9 @@ static void create_local_static_variable(entity_t *entity)
set_entity_initializer(irentity, null_init);
}
- ir_graph *const old_current_ir_graph = current_ir_graph;
- current_ir_graph = get_const_code_irg();
-
+ PUSH_IRG(get_const_code_irg());
create_variable_initializer(entity);
-
- assert(current_ir_graph == get_const_code_irg());
- current_ir_graph = old_current_ir_graph;
+ POP_IRG();
}
@@ -4351,7 +4375,7 @@ static void create_local_declaration(entity_t *entity)
return;
case STORAGE_CLASS_EXTERN:
if (entity->kind == ENTITY_FUNCTION) {
- assert(entity->function.statement == NULL);
+ assert(entity->function.body == NULL);
(void)get_function_entity(entity, NULL);
} else {
create_global_variable(entity);
@@ -4362,7 +4386,7 @@ static void create_local_declaration(entity_t *entity)
case STORAGE_CLASS_AUTO:
case STORAGE_CLASS_REGISTER:
if (entity->kind == ENTITY_FUNCTION) {
- if (entity->function.statement != NULL) {
+ if (entity->function.body != NULL) {
ir_type *owner = get_irg_frame_type(current_ir_graph);
(void)get_function_entity(entity, owner);
entity->declaration.kind = DECLARATION_KIND_INNER_FUNCTION;
@@ -4377,7 +4401,7 @@ static void create_local_declaration(entity_t *entity)
case STORAGE_CLASS_TYPEDEF:
break;
}
- panic("invalid storage class found");
+ panic("invalid storage class");
}
static void create_local_declarations(entity_t *e)
@@ -4454,109 +4478,62 @@ static ir_node *if_statement_to_firm(if_statement_t *statement)
create_local_declarations(statement->scope.entities);
/* Create the condition. */
- ir_node *true_block = NULL;
- ir_node *false_block = NULL;
- if (currently_reachable()) {
- true_block = new_immBlock();
- false_block = new_immBlock();
- create_condition_evaluation(statement->condition, true_block, false_block);
- mature_immBlock(true_block);
- mature_immBlock(false_block);
- }
+ jump_target true_target;
+ jump_target false_target;
+ init_jump_target(&true_target, NULL);
+ init_jump_target(&false_target, NULL);
+ if (currently_reachable())
+ create_condition_evaluation(statement->condition, &true_target, &false_target);
+
+ jump_target exit_target;
+ init_jump_target(&exit_target, NULL);
/* Create the true statement. */
- set_cur_block(true_block);
+ enter_jump_target(&true_target);
statement_to_firm(statement->true_statement);
- ir_node *fallthrough_block = get_cur_block();
+ jump_to_target(&exit_target);
/* Create the false statement. */
- set_cur_block(false_block);
- if (statement->false_statement != NULL) {
+ enter_jump_target(&false_target);
+ if (statement->false_statement)
statement_to_firm(statement->false_statement);
- }
-
- /* Handle the block after the if-statement. Minor simplification and
- * optimisation: Reuse the false/true block as fallthrough block, if the
- * true/false statement does not pass control to the fallthrough block, e.g.
- * in the typical if (x) return; pattern. */
- if (fallthrough_block) {
- if (currently_reachable()) {
- ir_node *const t_jump = new_r_Jmp(fallthrough_block);
- ir_node *const f_jump = new_Jmp();
- ir_node *const in[] = { t_jump, f_jump };
- fallthrough_block = new_Block(2, in);
- }
- set_cur_block(fallthrough_block);
- }
+ jump_to_target(&exit_target);
+ enter_jump_target(&exit_target);
return NULL;
}
-/**
- * Add an unconditional jump to the target block. If the source block is not
- * reachable, then a Bad predecessor is created to prevent Phi-less unreachable
- * loops. This is necessary if the jump potentially enters a loop.
- */
-static void jump_to(ir_node *const target_block)
-{
- ir_node *const pred = currently_reachable() ? new_Jmp() : new_Bad(mode_X);
- add_immBlock_pred(target_block, pred);
-}
-
-/**
- * Add an unconditional jump to the target block, if the current block is
- * reachable and do nothing otherwise. This is only valid if the jump does not
- * enter a loop (a back edge is ok).
- */
-static void jump_if_reachable(ir_node *const target_block)
-{
- if (currently_reachable())
- add_immBlock_pred(target_block, new_Jmp());
-}
-
-static ir_node *get_break_label(void)
-{
- if (break_label == NULL) {
- break_label = new_immBlock();
- }
- return break_label;
-}
-
static ir_node *do_while_statement_to_firm(do_while_statement_t *statement)
{
create_local_declarations(statement->scope.entities);
- /* create the header block */
- ir_node *header_block = new_immBlock();
-
- /* the loop body */
- ir_node *body_block = new_immBlock();
- jump_to(body_block);
-
- ir_node *old_continue_label = continue_label;
- ir_node *old_break_label = break_label;
- continue_label = header_block;
- break_label = NULL;
+ PUSH_BREAK(NULL);
+ PUSH_CONTINUE(NULL);
- set_cur_block(body_block);
- statement_to_firm(statement->body);
- ir_node *const false_block = get_break_label();
-
- assert(continue_label == header_block);
- continue_label = old_continue_label;
- break_label = old_break_label;
-
- jump_if_reachable(header_block);
-
- /* create the condition */
- mature_immBlock(header_block);
- set_cur_block(header_block);
-
- create_condition_evaluation(statement->condition, body_block, false_block);
- mature_immBlock(body_block);
- mature_immBlock(false_block);
-
- set_cur_block(false_block);
+ expression_t *const cond = statement->condition;
+ /* Avoid an explicit body block in case of do ... while (0);. */
+ if (is_constant_expression(cond) == EXPR_CLASS_CONSTANT && !fold_constant_to_bool(cond)) {
+ /* do ... while (0);. */
+ statement_to_firm(statement->body);
+ jump_to_target(&continue_target);
+ enter_jump_target(&continue_target);
+ jump_to_target(&break_target);
+ } else {
+ jump_target body_target;
+ init_jump_target(&body_target, NULL);
+ jump_to_target(&body_target);
+ enter_immature_jump_target(&body_target);
+ keep_loop();
+ statement_to_firm(statement->body);
+ jump_to_target(&continue_target);
+ if (enter_jump_target(&continue_target))
+ create_condition_evaluation(statement->condition, &body_target, &break_target);
+ enter_jump_target(&body_target);
+ }
+ enter_jump_target(&break_target);
+
+ POP_CONTINUE();
+ POP_BREAK();
return NULL;
}
@@ -4579,78 +4556,40 @@ static ir_node *for_statement_to_firm(for_statement_t *statement)
}
/* Create the header block */
- ir_node *const header_block = new_immBlock();
- jump_to(header_block);
+ jump_target header_target;
+ init_jump_target(&header_target, NULL);
+ jump_to_target(&header_target);
+ enter_immature_jump_target(&header_target);
+ keep_loop();
+
+ expression_t *const step = statement->step;
+ PUSH_BREAK(NULL);
+ PUSH_CONTINUE(step ? NULL : header_target.block);
/* Create the condition. */
- ir_node *body_block;
- ir_node *false_block;
expression_t *const cond = statement->condition;
if (cond && (is_constant_expression(cond) != EXPR_CLASS_CONSTANT || !fold_constant_to_bool(cond))) {
- body_block = new_immBlock();
- false_block = new_immBlock();
-
- set_cur_block(header_block);
- create_condition_evaluation(cond, body_block, false_block);
- mature_immBlock(body_block);
- } else {
- /* for-ever. */
- body_block = header_block;
- false_block = NULL;
-
- keep_alive(header_block);
- keep_all_memory(header_block);
+ jump_target body_target;
+ init_jump_target(&body_target, NULL);
+ create_condition_evaluation(cond, &body_target, &break_target);
+ enter_jump_target(&body_target);
}
- /* Create the step block, if necessary. */
- ir_node * step_block = header_block;
- expression_t *const step = statement->step;
- if (step != NULL) {
- step_block = new_immBlock();
- }
-
- ir_node *const old_continue_label = continue_label;
- ir_node *const old_break_label = break_label;
- continue_label = step_block;
- break_label = false_block;
-
/* Create the loop body. */
- set_cur_block(body_block);
statement_to_firm(statement->body);
- jump_if_reachable(step_block);
+ jump_to_target(&continue_target);
/* Create the step code. */
- if (step != NULL) {
- mature_immBlock(step_block);
- set_cur_block(step_block);
+ if (step && enter_jump_target(&continue_target)) {
expression_to_firm(step);
- jump_if_reachable(header_block);
+ jump_to_target(&header_target);
}
- mature_immBlock(header_block);
- assert(false_block == NULL || false_block == break_label);
- false_block = break_label;
- if (false_block != NULL) {
- mature_immBlock(false_block);
- }
- set_cur_block(false_block);
-
- assert(continue_label == step_block);
- continue_label = old_continue_label;
- break_label = old_break_label;
- return NULL;
-}
-
-static ir_node *create_jump_statement(const statement_t *statement, ir_node *target_block)
-{
- if (!currently_reachable())
- return NULL;
-
- dbg_info *dbgi = get_dbg_info(&statement->base.source_position);
- ir_node *jump = new_d_Jmp(dbgi);
- add_immBlock_pred(target_block, jump);
+ enter_jump_target(&header_target);
+ enter_jump_target(&break_target);
- set_unreachable_now();
+ POP_CONTINUE();
+ POP_BREAK();
return NULL;
}
@@ -4678,11 +4617,9 @@ static ir_switch_table *create_switch_table(const switch_statement_t *statement)
}
if (l->is_empty_range)
continue;
- ir_tarval *min = fold_constant_to_tarval(l->expression);
- ir_tarval *max = min;
+ ir_tarval *min = l->first_case;
+ ir_tarval *max = l->last_case;
long pn = (long) i+1;
- if (l->end_range != NULL)
- max = fold_constant_to_tarval(l->end_range);
ir_switch_table_set(res, i++, min, max, pn);
l->pn = pn;
}
@@ -4704,53 +4641,44 @@ static ir_node *switch_statement_to_firm(switch_statement_t *statement)
set_unreachable_now();
+ PUSH_BREAK(NULL);
ir_node *const old_switch = current_switch;
- ir_node *const old_break_label = break_label;
const bool old_saw_default_label = saw_default_label;
saw_default_label = false;
current_switch = switch_node;
- break_label = NULL;
statement_to_firm(statement->body);
-
- if (currently_reachable()) {
- add_immBlock_pred(get_break_label(), new_Jmp());
- }
+ jump_to_target(&break_target);
if (!saw_default_label && switch_node) {
ir_node *proj = new_d_Proj(dbgi, switch_node, mode_X, pn_Switch_default);
- add_immBlock_pred(get_break_label(), proj);
+ add_pred_to_jump_target(&break_target, proj);
}
- if (break_label != NULL) {
- mature_immBlock(break_label);
- }
- set_cur_block(break_label);
+ enter_jump_target(&break_target);
assert(current_switch == switch_node);
current_switch = old_switch;
- break_label = old_break_label;
saw_default_label = old_saw_default_label;
+ POP_BREAK();
return NULL;
}
static ir_node *case_label_to_firm(const case_label_statement_t *statement)
{
- if (statement->is_empty_range)
- return NULL;
+ if (current_switch != NULL && !statement->is_empty_range) {
+ jump_target case_target;
+ init_jump_target(&case_target, NULL);
- if (current_switch != NULL) {
- ir_node *block = new_immBlock();
/* Fallthrough from previous case */
- jump_if_reachable(block);
+ jump_to_target(&case_target);
- ir_node *const proj = new_Proj(current_switch, mode_X, statement->pn);
- add_immBlock_pred(block, proj);
+ ir_node *const proj = new_Proj(current_switch, mode_X, statement->pn);
+ add_pred_to_jump_target(&case_target, proj);
if (statement->expression == NULL)
saw_default_label = true;
- mature_immBlock(block);
- set_cur_block(block);
+ enter_jump_target(&case_target);
}
return statement_to_firm(statement->statement);
@@ -4758,32 +4686,41 @@ static ir_node *case_label_to_firm(const case_label_statement_t *statement)
static ir_node *label_to_firm(const label_statement_t *statement)
{
- ir_node *block = get_label_block(statement->label);
- jump_to(block);
-
- set_cur_block(block);
- keep_alive(block);
- keep_all_memory(block);
+ label_t *const label = statement->label;
+ prepare_label_target(label);
+ jump_to_target(&label->target);
+ if (--label->n_users == 0) {
+ enter_jump_target(&label->target);
+ } else {
+ enter_immature_jump_target(&label->target);
+ keep_loop();
+ }
return statement_to_firm(statement->statement);
}
-static ir_node *computed_goto_to_firm(computed_goto_statement_t const *const statement)
+static ir_node *goto_statement_to_firm(goto_statement_t *const stmt)
{
- if (!currently_reachable())
- return NULL;
-
- ir_node *const irn = expression_to_firm(statement->expression);
- dbg_info *const dbgi = get_dbg_info(&statement->base.source_position);
- ir_node *const ijmp = new_d_IJmp(dbgi, irn);
-
- set_irn_link(ijmp, ijmp_list);
- ijmp_list = ijmp;
-
+ label_t *const label = stmt->label;
+ prepare_label_target(label);
+ jump_to_target(&label->target);
+ if (--label->n_users == 0)
+ enter_jump_target(&label->target);
set_unreachable_now();
return NULL;
}
+static ir_node *computed_goto_to_firm(computed_goto_statement_t const *const statement)
+{
+ if (currently_reachable()) {
+ ir_node *const op = expression_to_firm(statement->expression);
+ ARR_APP1(ir_node*, ijmp_ops, op);
+ jump_to_target(&ijmp_target);
+ set_unreachable_now();
+ }
+ return NULL;
+}
+
static ir_node *asm_statement_to_firm(const asm_statement_t *statement)
{
bool needs_memory = statement->is_volatile;
@@ -5048,6 +4985,7 @@ static ir_node *statement_to_firm(statement_t *const stmt)
case STATEMENT_EMPTY: return NULL; /* nothing */
case STATEMENT_EXPRESSION: return expression_statement_to_firm( &stmt->expression);
case STATEMENT_FOR: return for_statement_to_firm( &stmt->fors);
+ case STATEMENT_GOTO: return goto_statement_to_firm( &stmt->gotos);
case STATEMENT_IF: return if_statement_to_firm( &stmt->ifs);
case STATEMENT_LABEL: return label_to_firm( &stmt->label);
case STATEMENT_LEAVE: return leave_statement_to_firm( &stmt->leave);
@@ -5055,11 +4993,17 @@ static ir_node *statement_to_firm(statement_t *const stmt)
case STATEMENT_RETURN: return return_statement_to_firm( &stmt->returns);
case STATEMENT_SWITCH: return switch_statement_to_firm( &stmt->switchs);
- case STATEMENT_BREAK: return create_jump_statement(stmt, get_break_label());
- case STATEMENT_CONTINUE: return create_jump_statement(stmt, continue_label);
- case STATEMENT_GOTO: return create_jump_statement(stmt, get_label_block(stmt->gotos.label));
+ {
+ jump_target *tgt;
+ case STATEMENT_BREAK: tgt = &break_target; goto jump;
+ case STATEMENT_CONTINUE: tgt = &continue_target; goto jump;
+jump:
+ jump_to_target(tgt);
+ set_unreachable_now();
+ return NULL;
+ }
- case STATEMENT_ERROR: panic("error statement found");
+ case STATEMENT_ERROR: panic("error statement");
}
panic("statement not implemented");
}
@@ -5071,8 +5015,7 @@ static int count_local_variables(const entity_t *entity,
entity_t const *const end = last != NULL ? last->base.next : NULL;
for (; entity != end; entity = entity->base.next) {
if ((entity->kind == ENTITY_VARIABLE || entity->kind == ENTITY_PARAMETER) &&
- !entity->variable.address_taken &&
- is_type_scalar(skip_typeref(entity->declaration.type)))
+ !var_needs_entity(&entity->variable))
++count;
}
return count;
@@ -5111,7 +5054,7 @@ static int get_function_n_local_vars(entity_t *entity)
count += count_local_variables(function->parameters.entities, NULL);
/* count local variables declared in body */
- walk_statements(function->statement, count_local_variables_in_stmt, &count);
+ walk_statements(function->body, count_local_variables_in_stmt, &count);
return count;
}
@@ -5148,14 +5091,12 @@ static void initialize_function_parameters(entity_t *entity)
assert(parameter->declaration.kind == DECLARATION_KIND_UNKNOWN);
type_t *type = skip_typeref(parameter->declaration.type);
- assert(!is_type_array(type));
- bool const needs_entity = parameter->variable.address_taken || is_type_compound(type);
-
- ir_type *param_irtype = get_method_param_type(function_irtype, n);
- if (needs_entity) {
+ dbg_info *const dbgi = get_dbg_info(&parameter->base.source_position);
+ ir_type *const param_irtype = get_method_param_type(function_irtype, n);
+ if (var_needs_entity(&parameter->variable)) {
ir_type *frame_type = get_irg_frame_type(irg);
ir_entity *param
- = new_parameter_entity(frame_type, n, param_irtype);
+ = new_d_parameter_entity(frame_type, n, param_irtype, dbgi);
parameter->declaration.kind = DECLARATION_KIND_PARAMETER_ENTITY;
parameter->variable.v.entity = param;
continue;
@@ -5163,7 +5104,7 @@ static void initialize_function_parameters(entity_t *entity)
ir_mode *param_mode = get_type_mode(param_irtype);
long pn = n;
- ir_node *value = new_r_Proj(args, param_mode, pn);
+ ir_node *value = new_rd_Proj(dbgi, args, param_mode, pn);
ir_mode *mode = get_ir_mode_storage(type);
value = create_conv(NULL, value, mode);
@@ -5178,32 +5119,6 @@ static void initialize_function_parameters(entity_t *entity)
}
}
-/**
- * Handle additional decl modifiers for IR-graphs
- *
- * @param irg the IR-graph
- * @param dec_modifiers additional modifiers
- */
-static void handle_decl_modifier_irg(ir_graph *irg,
- decl_modifiers_t decl_modifiers)
-{
- if (decl_modifiers & DM_NAKED) {
- /* TRUE if the declaration includes the Microsoft
- __declspec(naked) specifier. */
- add_irg_additional_properties(irg, mtp_property_naked);
- }
- if (decl_modifiers & DM_FORCEINLINE) {
- /* TRUE if the declaration includes the
- Microsoft __forceinline specifier. */
- set_irg_inline_property(irg, irg_inline_forced);
- }
- if (decl_modifiers & DM_NOINLINE) {
- /* TRUE if the declaration includes the Microsoft
- __declspec(noinline) specifier. */
- set_irg_inline_property(irg, irg_inline_forbidden);
- }
-}
-
static void add_function_pointer(ir_type *segment, ir_entity *method,
const char *unique_template)
{
@@ -5228,17 +5143,6 @@ static void add_function_pointer(ir_type *segment, ir_entity *method,
}
/**
- * Generate possible IJmp branches to a given label block.
- */
-static void gen_ijmp_branches(ir_node *block)
-{
- ir_node *ijmp;
- for (ijmp = ijmp_list; ijmp != NULL; ijmp = get_irn_link(ijmp)) {
- add_immBlock_pred(block, ijmp);
- }
-}
-
-/**
* Create code for a function and all inner functions.
*
* @param entity the function entity
@@ -5248,7 +5152,7 @@ static void create_function(entity_t *entity)
assert(entity->kind == ENTITY_FUNCTION);
ir_entity *function_entity = get_function_entity(entity, current_outer_frame);
- if (entity->function.statement == NULL)
+ if (entity->function.body == NULL)
return;
inner_functions = NULL;
@@ -5267,9 +5171,11 @@ static void create_function(entity_t *entity)
current_function_name = NULL;
current_funcsig = NULL;
- assert(all_labels == NULL);
- all_labels = NEW_ARR_F(label_t *, 0);
- ijmp_list = NULL;
+ assert(!ijmp_ops);
+ assert(!ijmp_blocks);
+ init_jump_target(&ijmp_target, NULL);
+ ijmp_ops = NEW_ARR_F(ir_node*, 0);
+ ijmp_blocks = NEW_ARR_F(ir_node*, 0);
int n_local_vars = get_function_n_local_vars(entity);
ir_graph *irg = new_ir_graph(function_entity, n_local_vars);
@@ -5286,16 +5192,11 @@ static void create_function(entity_t *entity)
set_irn_dbg_info(get_irg_start_block(irg),
get_entity_dbg_info(function_entity));
- /* set inline flags */
- if (entity->function.is_inline)
- set_irg_inline_property(irg, irg_inline_recomended);
- handle_decl_modifier_irg(irg, entity->declaration.modifiers);
-
next_value_number_function = 0;
initialize_function_parameters(entity);
current_static_link = entity->function.static_link;
- statement_to_firm(entity->function.statement);
+ statement_to_firm(entity->function.body);
ir_node *end_block = get_irg_end_block(irg);
@@ -5323,16 +5224,21 @@ static void create_function(entity_t *entity)
add_immBlock_pred(end_block, ret);
}
- for (int i = ARR_LEN(all_labels) - 1; i >= 0; --i) {
- label_t *label = all_labels[i];
- if (label->address_taken) {
- gen_ijmp_branches(label->block);
+ if (enter_jump_target(&ijmp_target)) {
+ size_t const n = ARR_LEN(ijmp_ops);
+ ir_node *const op = n == 1 ? ijmp_ops[0] : new_Phi(n, ijmp_ops, get_irn_mode(ijmp_ops[0]));
+ ir_node *const ijmp = new_IJmp(op);
+ for (size_t i = ARR_LEN(ijmp_blocks); i-- != 0;) {
+ ir_node *const block = ijmp_blocks[i];
+ add_immBlock_pred(block, ijmp);
+ mature_immBlock(block);
}
- mature_immBlock(label->block);
}
- DEL_ARR_F(all_labels);
- all_labels = NULL;
+ DEL_ARR_F(ijmp_ops);
+ DEL_ARR_F(ijmp_blocks);
+ ijmp_ops = NULL;
+ ijmp_blocks = NULL;
irg_finalize_cons(irg);
@@ -5450,8 +5356,7 @@ static void init_ir_types(void)
return;
ir_types_initialized = 1;
- ir_type_char = get_ir_type(type_char);
- ir_type_wchar_t = get_ir_type(type_wchar_t);
+ ir_type_char = get_ir_type(type_char);
be_params = be_get_backend_param();
mode_float_arithmetic = be_params->mode_float_arithmetic;
@@ -5507,8 +5412,8 @@ void translation_unit_to_firm(translation_unit_t *unit)
ir_set_uninitialized_local_variable_func(uninitialized_local_var);
/* just to be sure */
- continue_label = NULL;
- break_label = NULL;
+ init_jump_target(&break_target, NULL);
+ init_jump_target(&continue_target, NULL);
current_switch = NULL;
current_translation_unit = unit;
diff --git a/ast2firm.h b/ast2firm.h
index b941f3c..2271f66 100644
--- a/ast2firm.h
+++ b/ast2firm.h
@@ -36,6 +36,9 @@ typedef ident* (*create_ld_ident_func)(entity_t *entity);
void set_create_ld_ident(create_ld_ident_func func);
+ir_tarval *fold_constant_to_tarval(const expression_t *expression);
+void determine_enum_values(enum_type_t *type);
+
extern fp_model_t firm_fp_model;
extern ir_mode *atomic_modes[ATOMIC_TYPE_LAST+1];
diff --git a/ast_t.h b/ast_t.h
index 1dc06c3..7e72895 100644
--- a/ast_t.h
+++ b/ast_t.h
@@ -552,8 +552,8 @@ struct case_label_statement_t {
expression_t *end_range; /**< For GNUC case a .. b: the end range expression, NULL else. */
case_label_statement_t *next; /**< link to the next case label in switch */
statement_t *statement;
- long first_case; /**< The folded value of expression. */
- long last_case; /**< The folded value of end_range. */
+ ir_tarval *first_case;
+ ir_tarval *last_case;
bool is_bad; /**< If set marked as bad to suppress warnings. */
bool is_empty_range; /**< If set marked this as an empty range. */
long pn;
@@ -601,12 +601,18 @@ struct asm_clobber_t {
asm_clobber_t *next;
};
+struct asm_label_t {
+ label_t *label;
+ asm_label_t *next;
+};
+
struct asm_statement_t {
statement_base_t base;
string_t asm_text;
asm_argument_t *inputs;
asm_argument_t *outputs;
asm_clobber_t *clobbers;
+ asm_label_t *labels;
bool is_volatile;
};
diff --git a/attribute.c b/attribute.c
index 71f91d3..c8472c8 100644
--- a/attribute.c
+++ b/attribute.c
@@ -188,15 +188,11 @@ static void handle_attribute_aligned(const attribute_t *attribute,
}
if (!is_po2(alignment)) {
- errorf(&attribute->source_position,
- "alignment must be a power of 2 but is %d\n",
- alignment);
+ errorf(&attribute->source_position, "alignment must be a power of 2 but is %d", alignment);
return;
}
if (alignment <= 0) {
- errorf(&attribute->source_position,
- "alignment must be bigger than 0 but is %d\n",
- alignment);
+ errorf(&attribute->source_position, "alignment must be bigger than 0 but is %d", alignment);
return;
}
@@ -513,7 +509,7 @@ static bool attribute_argument_equal(const attribute_argument_t *arg1,
/* TODO */
return false;
}
- panic("Unknown argument type found");
+ panic("unknown argument type");
}
static bool attribute_arguments_equal(const attribute_argument_t *args1,
diff --git a/diagnostic.c b/diagnostic.c
index 27fdda9..0ca3df1 100644
--- a/diagnostic.c
+++ b/diagnostic.c
@@ -23,6 +23,7 @@
#include "diagnostic.h"
#include "adt/error.h"
#include "entity_t.h"
+#include "separator_t.h"
#include "symbol_t.h"
#include "token_t.h"
#include "ast.h"
@@ -185,18 +186,13 @@ done_flags:;
case 'k': {
if (extended) {
- bool first = true;
- va_list* toks = va_arg(ap, va_list*);
- const char* const delimiter = va_arg(ap, const char*);
+ va_list* const toks = va_arg(ap, va_list*);
+ separator_t sep = { "", va_arg(ap, const char*) };
for (;;) {
const token_kind_t tok = (token_kind_t)va_arg(*toks, int);
if (tok == 0)
break;
- if (first) {
- first = false;
- } else {
- fputs(delimiter, stderr);
- }
+ fputs(sep_next(&sep), stderr);
print_token_kind(stderr, tok);
}
} else {
@@ -247,10 +243,16 @@ void diagnosticf(const char *const fmt, ...)
static void diagnosticposvf(source_position_t const *const pos, char const *const kind, char const *const fmt, va_list ap)
{
FILE *const out = stderr;
- fprintf(out, "%s:%u:", pos->input_name, pos->lineno);
- if (show_column)
- fprintf(out, "%u:", (unsigned)pos->colno);
- fprintf(out, " %s: ", kind);
+ if (pos) {
+ fprintf(out, "%s:", pos->input_name);
+ if (pos->lineno != 0) {
+ fprintf(out, "%u:", pos->lineno);
+ if (show_column)
+ fprintf(out, "%u:", (unsigned)pos->colno);
+ }
+ fputc(' ', out);
+ }
+ fprintf(out, "%s: ", kind);
curr_pos = pos;
diagnosticvf(fmt, ap);
}
@@ -293,6 +295,8 @@ void warningf(warning_t const warn, source_position_t const* pos, char const *co
diagnosticposvf(pos, kind, fmt, ap);
if (diagnostics_show_option)
fprintf(stderr, " [-W%s]\n", s->name);
+ else
+ fputc('\n', stderr);
break;
default:
diff --git a/driver/firm_opt.c b/driver/firm_opt.c
index d5a05bd..f535c1c 100644
--- a/driver/firm_opt.c
+++ b/driver/firm_opt.c
@@ -130,8 +130,6 @@ static const struct params {
{ X("verify-off"), &firm_opt.verify, FIRM_VERIFICATION_OFF, "disable node verification" },
{ X("verify-on"), &firm_opt.verify, FIRM_VERIFICATION_ON, "enable node verification" },
{ X("verify-report"), &firm_opt.verify, FIRM_VERIFICATION_REPORT, "node verification, report only" },
- { X("check-all"), &firm_opt.check_all, 1, "enable checking all Firm phases" },
- { X("no-check-all"), &firm_opt.check_all, 0, "disable checking all Firm phases" },
/* dumping */
{ X("dump-ir"), &firm_dump.ir_graph, 1, "dump IR graph" },
@@ -281,6 +279,39 @@ static void rts_map(void)
static int *irg_dump_no;
+typedef enum opt_target {
+ OPT_TARGET_IRG, /**< optimization function works on a single graph */
+ OPT_TARGET_IRP /**< optimization function works on the complete program */
+} opt_target_t;
+
+typedef enum opt_flags {
+ OPT_FLAG_NONE = 0,
+ OPT_FLAG_ENABLED = 1 << 0, /**< enable the optimization */
+ OPT_FLAG_NO_DUMP = 1 << 1, /**< don't dump after transformation */
+ OPT_FLAG_NO_VERIFY = 1 << 2, /**< don't verify after transformation */
+ OPT_FLAG_HIDE_OPTIONS = 1 << 3, /**< do not automatically process
+ -foptions for this transformation */
+ OPT_FLAG_ESSENTIAL = 1 << 4, /**< output won't work without this pass
+ so we need it even with -O0 */
+} opt_flags_t;
+
+typedef void (*transform_irg_func)(ir_graph *irg);
+typedef void (*transform_irp_func)(void);
+
+typedef struct {
+ opt_target_t target;
+ const char *name;
+ union {
+ transform_irg_func transform_irg;
+ transform_irp_func transform_irp;
+ } u;
+ const char *description;
+ opt_flags_t flags;
+ ir_timer_t *timer;
+} opt_config_t;
+
+static opt_config_t *get_opt(const char *name);
+
static void do_stred(ir_graph *irg)
{
opt_osr(irg, osr_flag_default | osr_flag_keep_reg_pressure | osr_flag_ignore_x86_shift);
@@ -288,10 +319,15 @@ static void do_stred(ir_graph *irg)
static void after_inline_opt(ir_graph *irg)
{
+ opt_config_t *const config = get_opt("inline");
+ timer_stop(config->timer);
+
do_irg_opt(irg, "scalar-replace");
do_irg_opt(irg, "local");
do_irg_opt(irg, "control-flow");
do_irg_opt(irg, "combo");
+
+ timer_start(config->timer);
}
static void do_inline(void)
@@ -317,37 +353,6 @@ static void do_gcse(ir_graph *irg)
set_opt_global_cse(0);
}
-typedef enum opt_target {
- OPT_TARGET_IRG, /**< optimization function works on a single graph */
- OPT_TARGET_IRP /**< optimization function works on the complete program */
-} opt_target_t;
-
-typedef enum opt_flags {
- OPT_FLAG_NONE = 0,
- OPT_FLAG_ENABLED = 1 << 0, /**< enable the optimization */
- OPT_FLAG_NO_DUMP = 1 << 1, /**< don't dump after transformation */
- OPT_FLAG_NO_VERIFY = 1 << 2, /**< don't verify after transformation */
- OPT_FLAG_HIDE_OPTIONS = 1 << 3, /**< do not automatically process
- -foptions for this transformation */
- OPT_FLAG_ESSENTIAL = 1 << 4, /**< output won't work without this pass
- so we need it even with -O0 */
-} opt_flags_t;
-
-typedef void (*transform_irg_func)(ir_graph *irg);
-typedef void (*transform_irp_func)(void);
-
-typedef struct {
- opt_target_t target;
- const char *name;
- union {
- transform_irg_func transform_irg;
- transform_irp_func transform_irp;
- } u;
- const char *description;
- opt_flags_t flags;
- ir_timer_t *timer;
-} opt_config_t;
-
static opt_config_t opts[] = {
#define IRG(a, b, c, d) { OPT_TARGET_IRG, a, .u.transform_irg = (transform_irg_func)b, c, d }
#define IRP(a, b, c, d) { OPT_TARGET_IRP, a, .u.transform_irp = b, c, d }
@@ -381,6 +386,8 @@ static opt_config_t opts[] = {
IRG("vrp", set_vrp_data, "value range propagation", OPT_FLAG_NONE),
IRP("inline", do_inline, "inlining", OPT_FLAG_NONE),
IRP("lower-const", lower_const_code, "lowering of constant code", OPT_FLAG_HIDE_OPTIONS | OPT_FLAG_NO_DUMP | OPT_FLAG_NO_VERIFY | OPT_FLAG_ESSENTIAL),
+ IRP("local-const", local_opts_const_code, "local optimisation of constant initializers",
+ OPT_FLAG_HIDE_OPTIONS | OPT_FLAG_NO_DUMP | OPT_FLAG_NO_VERIFY | OPT_FLAG_ESSENTIAL),
IRP("target-lowering", be_lower_for_target, "lowering necessary for target architecture", OPT_FLAG_HIDE_OPTIONS | OPT_FLAG_ESSENTIAL),
IRP("opt-func-call", optimize_funccalls, "function call optimization", OPT_FLAG_NONE),
IRP("opt-proc-clone", do_cloning, "procedure cloning", OPT_FLAG_NONE),
@@ -432,15 +439,15 @@ static bool do_irg_opt(ir_graph *irg, const char *name)
ir_graph *const old_irg = current_ir_graph;
current_ir_graph = irg;
- timer_push(config->timer);
+ timer_start(config->timer);
config->u.transform_irg(irg);
- timer_pop(config->timer);
+ timer_stop(config->timer);
if (firm_dump.all_phases && firm_dump.ir_graph) {
dump_ir_graph(irg, name);
}
- if (firm_opt.check_all) {
+ if (firm_opt.verify) {
timer_push(t_verify);
irg_verify(irg, VERIFY_ENFORCE_SSA);
timer_pop(t_verify);
@@ -457,9 +464,9 @@ static void do_irp_opt(const char *name)
if (! (config->flags & OPT_FLAG_ENABLED))
return;
- timer_push(config->timer);
+ timer_start(config->timer);
config->u.transform_irp();
- timer_pop(config->timer);
+ timer_stop(config->timer);
if (firm_dump.ir_graph && firm_dump.all_phases) {
int i;
@@ -469,7 +476,7 @@ static void do_irp_opt(const char *name)
}
}
- if (firm_opt.check_all) {
+ if (firm_opt.verify) {
int i;
timer_push(t_verify);
for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
@@ -491,6 +498,7 @@ static void enable_safe_defaults(void)
set_opt_enabled("control-flow", true);
set_opt_enabled("local", true);
set_opt_enabled("lower-const", true);
+ set_opt_enabled("local-const", true);
set_opt_enabled("scalar-replace", true);
set_opt_enabled("place", true);
set_opt_enabled("gcse", true);
@@ -539,8 +547,6 @@ static void do_firm_optimizations(const char *input_filename)
if (get_opt_enabled("ivopts"))
set_opt_enabled("remove-phi-cycles", false);
- timer_start(t_all_opt);
-
do_irp_opt("rts");
/* first step: kill dead code */
@@ -637,8 +643,6 @@ static void do_firm_optimizations(const char *input_filename)
if (firm_dump.statistic & STAT_AFTER_OPT)
stat_dump_snapshot(input_filename, "opt");
-
- timer_stop(t_all_opt);
}
/**
@@ -666,8 +670,6 @@ static void do_firm_lowering(const char *input_filename)
if (firm_dump.statistic & STAT_AFTER_LOWER)
stat_dump_snapshot(input_filename, "low");
- timer_start(t_all_opt);
-
for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
ir_graph *irg = get_irp_irg(i);
@@ -698,9 +700,9 @@ static void do_firm_lowering(const char *input_filename)
do_irg_opt(irg, "parallelize-mem");
do_irg_opt(irg, "frame");
}
+ do_irp_opt("local-const");
do_irp_opt("remove-unused");
do_irp_opt("opt-cc");
- timer_stop(t_all_opt);
dump_all("low-opt");
if (firm_dump.statistic & STAT_FINAL) {
@@ -773,18 +775,21 @@ void generate_code(FILE *out, const char *input_filename)
/* FIXME: cloning might ADD new graphs. */
irg_dump_no = calloc(get_irp_last_idx(), sizeof(*irg_dump_no));
+ ir_timer_init_parent(t_verify);
+ ir_timer_init_parent(t_vcg_dump);
+ timer_start(t_all_opt);
+
if (firm_dump.all_types) {
dump_ir_prog_ext(dump_typegraph, "types.vcg");
}
dump_all("");
- timer_push(t_verify);
- tr_verify();
- timer_pop(t_verify);
-
- /* all graphs are finalized, set the irp phase to high */
- set_irp_phase_state(phase_high);
+ if (firm_opt.verify) {
+ timer_push(t_verify);
+ tr_verify();
+ timer_pop(t_verify);
+ }
/* BEWARE: kill unreachable code before doing compound lowering */
for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
@@ -799,9 +804,7 @@ void generate_code(FILE *out, const char *input_filename)
do_firm_optimizations(input_filename);
do_firm_lowering(input_filename);
- /* set the phase to low */
- for (i = get_irp_n_irgs() - 1; i >= 0; --i)
- set_irg_phase_state(get_irp_irg(i), phase_low);
+ timer_stop(t_all_opt);
if (firm_dump.statistic & STAT_FINAL_IR)
stat_dump_snapshot(input_filename, "final-ir");
diff --git a/driver/firm_timing.c b/driver/firm_timing.c
index 8503bc9..d41574a 100644
--- a/driver/firm_timing.c
+++ b/driver/firm_timing.c
@@ -45,9 +45,11 @@ void timer_term(FILE *f)
for (info = infos; info != NULL; info = next) {
ir_timer_t *timer = info->timer;
- double val = (double)ir_timer_elapsed_usec(timer) / 1000.0;
- const char *description = info->description;
- fprintf(f, "%-45s %8.3f msec\n", description, val);
+ if (f != NULL) {
+ double val = (double)ir_timer_elapsed_usec(timer) / 1000.0;
+ const char *description = info->description;
+ fprintf(f, "%-45s %8.3f msec\n", description, val);
+ }
ir_timer_free(timer);
xfree(info->description);
@@ -68,9 +70,8 @@ void timer_push(ir_timer_t *timer)
void timer_pop(ir_timer_t *timer)
{
- (void) timer;
if (timers_inited)
- ir_timer_pop();
+ ir_timer_pop(timer);
}
void timer_start(ir_timer_t *timer)
diff --git a/entity.c b/entity.c
index 3a2db26..353c770 100644
--- a/entity.c
+++ b/entity.c
@@ -45,7 +45,7 @@ const char *get_entity_kind_name(entity_kind_t kind)
case ENTITY_NAMESPACE: return "namespace";
}
- panic("Invalid entity kind encountered in get_entity_kind_name");
+ panic("invalid entity kind");
}
/**
diff --git a/entity_t.h b/entity_t.h
index dc20fd5..e1a26ed 100644
--- a/entity_t.h
+++ b/entity_t.h
@@ -25,6 +25,7 @@
#include "attribute.h"
#include <libfirm/firm_types.h>
#include "builtins.h"
+#include "jump_target.h"
#include "token_t.h"
typedef enum {
@@ -172,10 +173,12 @@ struct label_t {
entity_base_t base;
bool used : 1;
bool address_taken : 1;
+ unsigned n_users; /* Reference counter to mature the label block as early as possible. */
statement_t *statement;
/* ast2firm info */
- ir_node *block;
+ jump_target target;
+ ir_node *indirect_block;
};
struct namespace_t {
@@ -212,9 +215,6 @@ struct compound_member_t {
unsigned char bit_offset; /**< extra bit offset for bitfield members */
unsigned char bit_size; /**< bitsize for bitfield members */
bool bitfield : 1; /**< member is (part of) a bitfield */
- bool read : 1;
- bool address_taken : 1; /**< Set if the address of this
- declaration was taken. */
/* ast2firm info */
ir_entity *entity;
@@ -223,9 +223,6 @@ struct compound_member_t {
struct variable_t {
declaration_t base;
bool thread_local : 1;
- bool restricta : 1;
- bool deprecated : 1;
- bool noalias : 1;
bool address_taken : 1; /**< Set if the address of this declaration was taken. */
bool read : 1;
@@ -251,7 +248,7 @@ struct function_t {
builtin_kind_t btk;
scope_t parameters;
- statement_t *statement;
+ statement_t *body;
symbol_t *actual_name; /**< gnu extension __REDIRECT */
/* ast2firm info */
diff --git a/input.c b/input.c
index 02f5dce..fa2ae92 100644
--- a/input.c
+++ b/input.c
@@ -1,5 +1,6 @@
#include "config.h"
+#include "diagnostic.h"
#include "input.h"
#include <ctype.h>
@@ -294,21 +295,16 @@ static int my_strcasecmp(const char *s1, const char *s2)
static void choose_decoder(input_t *result, const char *encoding)
{
- if (encoding == NULL) {
- result->decode = decode_utf8;
- } else {
+ if (encoding) {
for (named_decoder_t const *i = decoders; i->name != NULL; ++i) {
if (my_strcasecmp(encoding, i->name) != 0)
continue;
result->decode = i->decoder;
- break;
- }
- if (result->decode == NULL) {
- fprintf(stderr, "error: input encoding \"%s\" not supported\n",
- encoding);
- result->decode = decode_utf8;
+ return;
}
+ errorf(NULL, "input encoding \"%s\" not supported", encoding);
}
+ result->decode = decode_utf8;
}
input_t *input_from_stream(FILE *file, const char *encoding)
diff --git a/jump_target.c b/jump_target.c
new file mode 100644
index 0000000..04d90c5
--- /dev/null
+++ b/jump_target.c
@@ -0,0 +1,65 @@
+#include "adt/util.h"
+#include "jump_target.h"
+
+void jump_from_block_to_target(jump_target *const tgt, ir_node *const block)
+{
+ if (!tgt->block) {
+ tgt->block = block;
+ tgt->first = true;
+ return;
+ } else if (tgt->first) {
+ ir_node *const jmp = new_r_Jmp(tgt->block);
+ tgt->block = new_immBlock();
+ tgt->first = false;
+ add_immBlock_pred(tgt->block, jmp);
+ }
+ ir_node *const jmp = new_r_Jmp(block);
+ add_immBlock_pred(tgt->block, jmp);
+}
+
+void jump_to_target(jump_target *const tgt)
+{
+ ir_node *const block = get_cur_block();
+ if (block)
+ jump_from_block_to_target(tgt, block);
+}
+
+void add_pred_to_jump_target(jump_target *const tgt, ir_node *const pred)
+{
+ if (!tgt->block) {
+ tgt->block = new_immBlock();
+ } else if (tgt->first) {
+ ir_node *const jmp = new_r_Jmp(tgt->block);
+ tgt->block = new_immBlock();
+ tgt->first = false;
+ add_immBlock_pred(tgt->block, jmp);
+ }
+ add_immBlock_pred(tgt->block, pred);
+}
+
+ir_node *enter_jump_target(jump_target *const tgt)
+{
+ ir_node *const block = tgt->block;
+ if (block && !tgt->first)
+ mature_immBlock(block);
+ set_cur_block(block);
+ return block;
+}
+
+void enter_immature_jump_target(jump_target *const tgt)
+{
+ ir_node *jmp;
+ ir_node *block = tgt->block;
+ if (!block) {
+ /* Avoid unreachable loops by adding a Bad entry. */
+ jmp = new_Bad(mode_X);
+ goto new_block;
+ } else if (tgt->first) {
+ tgt->first = false;
+ jmp = new_r_Jmp(block);
+new_block:
+ tgt->block = block = new_immBlock();
+ add_immBlock_pred(block, jmp);
+ }
+ set_cur_block(block);
+}
diff --git a/jump_target.h b/jump_target.h
new file mode 100644
index 0000000..dd9d9a9
--- /dev/null
+++ b/jump_target.h
@@ -0,0 +1,28 @@
+#ifndef JUMP_TARGET_H
+#define JUMP_TARGET_H
+
+#include <libfirm/firm.h>
+#include <stdbool.h>
+
+typedef struct jump_target {
+ ir_node *block;
+ bool first;
+} jump_target;
+
+static inline void init_jump_target(jump_target *const tgt, ir_node *const block)
+{
+ tgt->block = block;
+ tgt->first = false;
+}
+
+void jump_from_block_to_target(jump_target *tgt, ir_node *block);
+
+void jump_to_target(jump_target *tgt);
+
+void add_pred_to_jump_target(jump_target *tgt, ir_node *pred);
+
+ir_node *enter_jump_target(jump_target *tgt);
+
+void enter_immature_jump_target(jump_target *tgt);
+
+#endif
diff --git a/libfirm b/libfirm
-Subproject ad95da81e725f83865020dd6d86a55046d27f72
+Subproject de39228971e6591d409cdbd6bf89af43c27b8bb
diff --git a/main.c b/main.c
index 3cd9c95..41a5aee 100644
--- a/main.c
+++ b/main.c
@@ -59,6 +59,7 @@
#include <libfirm/firm.h>
#include <libfirm/be.h>
+#include <libfirm/statev.h>
#include "preprocessor.h"
#include "token_t.h"
@@ -224,7 +225,7 @@ static void do_parsing(compilation_unit_t *unit)
{
ir_timer_t *t_parsing = ir_timer_new();
timer_register(t_parsing, "Frontend: Parsing");
- timer_push(t_parsing);
+ timer_start(t_parsing);
start_parsing();
@@ -239,7 +240,10 @@ static void do_parsing(compilation_unit_t *unit)
unit->type = COMPILATION_UNIT_AST;
unit->parse_errors = error_count > 0 || !res;
- timer_pop(t_parsing);
+ timer_stop(t_parsing);
+ if (stat_ev_enabled) {
+ stat_ev_dbl("time_parsing", ir_timer_elapsed_sec(t_parsing));
+ }
}
static void add_flag(struct obstack *obst, const char *format, ...)
@@ -390,7 +394,8 @@ static bool run_external_preprocessor(compilation_unit_t *unit)
}
FILE *f = popen(commandline, "r");
if (f == NULL) {
- fprintf(stderr, "invoking preprocessor failed\n");
+ source_position_t const pos = { unit->name, 0, 0, 0 };
+ errorf(&pos, "invoking preprocessor failed");
return false;
}
/* we do not really need that anymore */
@@ -441,7 +446,8 @@ static void assemble(const char *out, const char *in)
}
int err = system(commandline);
if (err != EXIT_SUCCESS) {
- fprintf(stderr, "assembler reported an error\n");
+ source_position_t const pos = { in, 0, 0, 0 };
+ errorf(&pos, "assembler reported an error");
exit(EXIT_FAILURE);
}
obstack_free(&asflags_obst, commandline);
@@ -473,7 +479,8 @@ static void print_file_name(const char *file)
}
int err = system(commandline);
if (err != EXIT_SUCCESS) {
- fprintf(stderr, "linker reported an error\n");
+ source_position_t const pos = { file, 0, 0, 0 };
+ errorf(&pos, "linker reported an error");
exit(EXIT_FAILURE);
}
obstack_free(&ldflags_obst, commandline);
@@ -543,13 +550,14 @@ static FILE *make_temp_file(const char *prefix, const char **name_result)
char *name = obstack_finish(&file_obst);
int fd = mkstemp(name);
if (fd == -1) {
- fprintf(stderr, "could not create temporary file: %s\n",
- strerror(errno));
+ source_position_t const pos = { name, 0, 0, 0 };
+ errorf(&pos, "could not create temporary file: %s", strerror(errno));
return NULL;
}
FILE *out = fdopen(fd, "w");
if (out == NULL) {
- fprintf(stderr, "could not open temporary file as FILE*\n");
+ source_position_t const pos = { name, 0, 0, 0 };
+ errorf(&pos, "could not open temporary file as FILE*");
return NULL;
}
@@ -781,6 +789,8 @@ static void print_help_debug(void)
put_help("--print-parenthesis", "");
put_help("--benchmark", "Preprocess and parse, produces no output");
put_help("--time", "Measure time of compiler passes");
+ put_help("--statev", "Produce statev output");
+ put_help("--filtev=filter", "Set statev filter regex");
put_help("--dump-function func", "Preprocess, parse and output vcg graph of func");
put_help("--export-ir", "Preprocess, parse and output compiler intermediate representation");
}
@@ -880,7 +890,7 @@ static bool parse_target_triple(const char *arg)
{
machine_triple_t *triple = firm_parse_machine_triple(arg);
if (triple == NULL) {
- fprintf(stderr, "Target-triple is not in the form 'cpu_type-manufacturer-operating_system'\n");
+ errorf(NULL, "target-triple '%s' is not in the form 'cpu_type-manufacturer-operating_system'", arg);
return false;
}
target_machine = triple;
@@ -924,7 +934,7 @@ static const char *setup_isa_from_tripel(const machine_triple_t *machine)
} else if (streq(cpu, "arm")) {
return "arm";
} else {
- fprintf(stderr, "Unknown cpu '%s' in target-triple\n", cpu);
+ errorf(NULL, "unknown cpu '%s' in target-triple", cpu);
return NULL;
}
}
@@ -991,7 +1001,7 @@ static void init_types_and_adjust(void)
/* operating system ABI specifics */
if (firm_is_darwin_os(target_machine)) {
- if (machine_size == 32) {
+ if (is_ia32_cpu(target_machine->cpu_type)) {
props[ATOMIC_TYPE_LONGLONG].struct_alignment = 4;
props[ATOMIC_TYPE_ULONGLONG].struct_alignment = 4;
props[ATOMIC_TYPE_DOUBLE].struct_alignment = 4;
@@ -1000,7 +1010,11 @@ static void init_types_and_adjust(void)
props[ATOMIC_TYPE_LONG_DOUBLE].struct_alignment = 16;
}
} else if (firm_is_windows_os(target_machine)) {
- if (machine_size == 64) {
+ if (is_ia32_cpu(target_machine->cpu_type)) {
+ props[ATOMIC_TYPE_LONGLONG].struct_alignment = 8;
+ props[ATOMIC_TYPE_ULONGLONG].struct_alignment = 8;
+ props[ATOMIC_TYPE_DOUBLE].struct_alignment = 8;
+ } else if (machine_size == 64) {
/* to ease porting of old c-code microsoft decided to use 32bits
* even for long */
props[ATOMIC_TYPE_LONG] = props[ATOMIC_TYPE_INT];
@@ -1011,8 +1025,6 @@ static void init_types_and_adjust(void)
props[ATOMIC_TYPE_LONG_DOUBLE] = props[ATOMIC_TYPE_DOUBLE];
} else if (firm_is_unixish_os(target_machine)) {
if (is_ia32_cpu(target_machine->cpu_type)) {
- /* System V has a broken alignment for double so we have to add
- * a hack here */
props[ATOMIC_TYPE_DOUBLE].struct_alignment = 4;
props[ATOMIC_TYPE_LONGLONG].struct_alignment = 4;
props[ATOMIC_TYPE_ULONGLONG].struct_alignment = 4;
@@ -1206,14 +1218,33 @@ static bool open_input(compilation_unit_t *unit)
} else {
unit->input = fopen(inputname, "r");
if (unit->input == NULL) {
- fprintf(stderr, "Could not open '%s': %s\n", inputname,
- strerror(errno));
+ source_position_t const pos = { inputname, 0, 0, 0 };
+ errorf(&pos, "could not open: %s", strerror(errno));
return false;
}
}
return true;
}
+static void node_counter(ir_node *node, void *env)
+{
+ (void)node;
+ unsigned long long *count = (unsigned long long*)env;
+ ++(*count);
+}
+
+static unsigned long long count_firm_nodes(void)
+{
+ unsigned long long count = 0;
+
+ int n_irgs = get_irp_n_irgs();
+ for (int i = 0; i < n_irgs; ++i) {
+ ir_graph *irg = get_irp_irg(i);
+ irg_walk_graph(irg, node_counter, NULL, &count);
+ }
+ return count;
+}
+
static int compilation_loop(compile_mode_t mode, compilation_unit_t *units,
lang_standard_t standard, FILE *out)
{
@@ -1225,20 +1256,22 @@ static int compilation_loop(compile_mode_t mode, compilation_unit_t *units,
determine_unit_standard(unit, standard);
setup_cmode(unit);
+ stat_ev_ctx_push_str("compilation_unit", inputname);
+
again:
switch (unit->type) {
case COMPILATION_UNIT_IR: {
bool res = open_input(unit);
if (!res) {
result = EXIT_FAILURE;
- continue;
+ break;
}
res = !ir_import_file(unit->input, unit->name);
if (!res) {
- fprintf(stderr, "Import of firm graph from '%s' failed\n",
- inputname);
+ source_position_t const pos = { inputname, 0, 0, 0 };
+ errorf(&pos, "import of firm graph failed");
result = EXIT_FAILURE;
- continue;
+ break;
}
unit->type = COMPILATION_UNIT_INTERMEDIATE_REPRESENTATION;
goto again;
@@ -1251,7 +1284,7 @@ again:
bool res = run_external_preprocessor(unit);
if (!res) {
result = EXIT_FAILURE;
- continue;
+ break;
}
goto again;
}
@@ -1262,7 +1295,7 @@ again:
bool res = open_input(unit);
if (!res) {
result = EXIT_FAILURE;
- continue;
+ break;
}
init_tokens();
@@ -1270,9 +1303,9 @@ again:
bool res = output_preprocessor_tokens(unit, out);
if (!res) {
result = EXIT_FAILURE;
- continue;
+ break;
}
- continue;
+ break;
}
/* do the actual parsing */
@@ -1306,20 +1339,24 @@ again:
/* build the firm graph */
ir_timer_t *t_construct = ir_timer_new();
timer_register(t_construct, "Frontend: Graph construction");
- timer_push(t_construct);
+ timer_start(t_construct);
if (already_constructed_firm) {
panic("compiling multiple files/translation units not possible");
}
init_implicit_optimizations();
translation_unit_to_firm(unit->ast);
already_constructed_firm = true;
- timer_pop(t_construct);
+ timer_stop(t_construct);
+ if (stat_ev_enabled) {
+ stat_ev_dbl("time_graph_construction", ir_timer_elapsed_sec(t_construct));
+ stat_ev_int("size_graph_construction", count_firm_nodes());
+ }
unit->type = COMPILATION_UNIT_INTERMEDIATE_REPRESENTATION;
goto again;
case COMPILATION_UNIT_INTERMEDIATE_REPRESENTATION:
if (mode == ParseOnly)
- continue;
+ break;
if (mode == CompileDump) {
/* find irg */
@@ -1336,8 +1373,7 @@ again:
}
if (irg == NULL) {
- fprintf(stderr, "No graph for function '%s' found\n",
- dumpfunction);
+ errorf(NULL, "no graph for function '%s' found", dumpfunction);
return EXIT_FAILURE;
}
@@ -1349,7 +1385,7 @@ again:
if (mode == CompileExportIR) {
ir_export_file(out);
if (ferror(out) != 0) {
- fprintf(stderr, "Error while writing to output\n");
+ errorf(NULL, "writing to output failed");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
@@ -1361,7 +1397,14 @@ again:
} else {
asm_out = make_temp_file("ccs", &unit->name);
}
+ ir_timer_t *t_opt_codegen = ir_timer_new();
+ timer_register(t_opt_codegen, "Optimization and Codegeneration");
+ timer_start(t_opt_codegen);
generate_code(asm_out, inputname);
+ timer_stop(t_opt_codegen);
+ if (stat_ev_enabled) {
+ stat_ev_dbl("time_opt_codegen", ir_timer_elapsed_sec(t_opt_codegen));
+ }
if (asm_out != out) {
fclose(asm_out);
}
@@ -1391,6 +1434,8 @@ again:
case COMPILATION_UNIT_OBJECT:
break;
}
+
+ stat_ev_ctx_pop("compilation_unit");
}
return result;
}
@@ -1429,7 +1474,7 @@ static int link_program(compilation_unit_t *units)
}
int err = system(commandline);
if (err != EXIT_SUCCESS) {
- fprintf(stderr, "linker reported an error\n");
+ errorf(NULL, "linker reported an error");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
@@ -1444,9 +1489,12 @@ int main(int argc, char **argv)
compilation_unit_t *units = NULL;
compilation_unit_t *last_unit = NULL;
bool construct_dep_target = false;
- bool do_timing = false;
+ bool produce_statev = false;
+ const char *filtev = NULL;
bool profile_generate = false;
bool profile_use = false;
+ bool do_timing = false;
+ bool print_timing = false;
/* hack for now... */
if (strstr(argv[0], "pptest") != NULL) {
@@ -1469,13 +1517,13 @@ int main(int argc, char **argv)
if (def[0] == '\0') { \
++i; \
if (i >= argc) { \
- fprintf(stderr, "error: expected argument after '" args "'\n"); \
+ errorf(NULL, "expected argument after '" args "'"); \
argument_errors = true; \
break; \
} \
def = argv[i]; \
if (def[0] == '-' && def[1] != '\0') { \
- fprintf(stderr, "error: expected argument after '" args "'\n"); \
+ errorf(NULL, "expected argument after '" args "'"); \
argument_errors = true; \
continue; \
} \
@@ -1562,7 +1610,7 @@ int main(int argc, char **argv)
GET_ARG_AFTER(opt, "-x");
forced_unittype = get_unit_type_from_string(opt);
if (forced_unittype == COMPILATION_UNIT_UNKNOWN) {
- fprintf(stderr, "Unknown language '%s'\n", opt);
+ errorf(NULL, "unknown language '%s'", opt);
argument_errors = true;
}
} else if (streq(option, "M")) {
@@ -1636,8 +1684,7 @@ int main(int argc, char **argv)
elf_visibility_tag_t visibility
= get_elf_visibility_from_string(val);
if (visibility == ELF_VISIBILITY_ERROR) {
- fprintf(stderr, "invalid visibility '%s' specified\n",
- val);
+ errorf(NULL, "invalid visibility '%s' specified", val);
argument_errors = true;
} else {
set_default_visibility(visibility);
@@ -1711,8 +1758,7 @@ int main(int argc, char **argv)
} else {
int res = firm_option(orig_opt);
if (res == 0) {
- fprintf(stderr, "error: unknown Firm option '-f%s'\n",
- orig_opt);
+ errorf(NULL, "unknown Firm option '-f%s'", orig_opt);
argument_errors = true;
continue;
}
@@ -1728,8 +1774,7 @@ int main(int argc, char **argv)
} else {
int res = be_parse_arg(opt);
if (res == 0) {
- fprintf(stderr, "error: unknown Firm backend option '-b %s'\n",
- opt);
+ errorf(NULL, "unknown Firm backend option '-b %s'", opt);
argument_errors = true;
} else if (strstart(opt, "isa=")) {
strncpy(cpu_arch, opt, sizeof(cpu_arch));
@@ -1793,7 +1838,7 @@ int main(int argc, char **argv)
res &= be_parse_arg(arch_opt);
if (res == 0) {
- fprintf(stderr, "Unknown architecture '%s'\n", arch_opt);
+ errorf(NULL, "unknown architecture '%s'", arch_opt);
argument_errors = true;
}
} else if (strstart(opt, "tune=")) {
@@ -1815,7 +1860,7 @@ int main(int argc, char **argv)
else if (streq(opt, "sse"))
opt = "sse2";
else {
- fprintf(stderr, "error: option -mfpmath supports only 387 or sse\n");
+ errorf(NULL, "option -mfpmath supports only 387 or sse");
argument_errors = true;
}
if (!argument_errors) {
@@ -1833,7 +1878,7 @@ int main(int argc, char **argv)
} else if (streq(opt, "rtd")) {
default_calling_convention = CC_STDCALL;
} else if (strstart(opt, "regparm=")) {
- fprintf(stderr, "error: regparm convention not supported yet\n");
+ errorf(NULL, "regparm convention not supported yet");
argument_errors = true;
} else if (streq(opt, "soft-float")) {
add_flag(&ldflags_obst, "-msoft-float");
@@ -1847,10 +1892,10 @@ int main(int argc, char **argv)
} else {
long int value = strtol(opt, NULL, 10);
if (value == 0) {
- fprintf(stderr, "error: wrong option '-m %s'\n", opt);
+ errorf(NULL, "wrong option '-m %s'", opt);
argument_errors = true;
} else if (value != 16 && value != 32 && value != 64) {
- fprintf(stderr, "error: option -m supports only 16, 32 or 64\n");
+ errorf(NULL, "option -m supports only 16, 32 or 64");
argument_errors = true;
} else {
unsigned machine_size = (unsigned)value;
@@ -1933,8 +1978,7 @@ int main(int argc, char **argv)
} else if (streq(option, "jna-limit")) {
++i;
if (i >= argc) {
- fprintf(stderr, "error: "
- "expected argument after '--jna-limit'\n");
+ errorf(NULL, "expected argument after '--jna-limit'");
argument_errors = true;
break;
}
@@ -1942,8 +1986,7 @@ int main(int argc, char **argv)
} else if (streq(option, "jna-libname")) {
++i;
if (i >= argc) {
- fprintf(stderr, "error: "
- "expected argument after '--jna-libname'\n");
+ errorf(NULL, "expected argument after '--jna-libname'");
argument_errors = true;
break;
}
@@ -1958,7 +2001,13 @@ int main(int argc, char **argv)
} else if (streq(option, "no-external-pp")) {
external_preprocessor = NULL;
} else if (streq(option, "time")) {
- do_timing = true;
+ do_timing = true;
+ print_timing = true;
+ } else if (streq(option, "statev")) {
+ do_timing = true;
+ produce_statev = true;
+ } else if (strstart(option, "filtev=")) {
+ GET_ARG_AFTER(filtev, "--filtev=");
} else if (streq(option, "version")) {
print_cparser_version();
return EXIT_SUCCESS;
@@ -1985,8 +2034,7 @@ int main(int argc, char **argv)
} else if (streq(option, "dump-function")) {
++i;
if (i >= argc) {
- fprintf(stderr, "error: "
- "expected argument after '--dump-function'\n");
+ errorf(NULL, "expected argument after '--dump-function'");
argument_errors = true;
break;
}
@@ -1997,11 +2045,11 @@ int main(int argc, char **argv)
} else if (streq(option, "unroll-loops")) {
/* ignore (gcc compatibility) */
} else {
- fprintf(stderr, "error: unknown argument '%s'\n", arg);
+ errorf(NULL, "unknown argument '%s'", arg);
argument_errors = true;
}
} else {
- fprintf(stderr, "error: unknown argument '%s'\n", arg);
+ errorf(NULL, "unknown argument '%s'", arg);
argument_errors = true;
}
} else {
@@ -2061,7 +2109,7 @@ int main(int argc, char **argv)
return EXIT_SUCCESS;
}
if (units == NULL) {
- fprintf(stderr, "error: no input files specified\n");
+ errorf(NULL, "no input files specified");
argument_errors = true;
}
@@ -2158,13 +2206,31 @@ int main(int argc, char **argv)
} else {
out = fopen(outname, "w");
if (out == NULL) {
- fprintf(stderr, "Could not open '%s' for writing: %s\n", outname,
- strerror(errno));
+ source_position_t const pos = { outname, 0, 0, 0 };
+ errorf(&pos, "could not open for writing: %s", strerror(errno));
return EXIT_FAILURE;
}
}
+ if (produce_statev && units != NULL) {
+ /* attempt to guess a good name for the file */
+ const char *first_cup = units->name;
+ if (first_cup != NULL) {
+ const char *dot = strrchr(first_cup, '.');
+ const char *pos = dot ? dot : first_cup + strlen(first_cup);
+ char buf[pos-first_cup+1];
+ strncpy(buf, first_cup, pos-first_cup);
+ buf[pos-first_cup] = '\0';
+
+ stat_ev_begin(buf, filtev);
+ }
+ }
+
int result = compilation_loop(mode, units, standard, out);
+ if (stat_ev_enabled) {
+ stat_ev_end();
+ }
+
if (result != EXIT_SUCCESS) {
if (out != stdout)
unlink(outname);
@@ -2182,7 +2248,7 @@ int main(int argc, char **argv)
}
if (do_timing)
- timer_term(stderr);
+ timer_term(print_timing ? stderr : NULL);
free_temp_files();
obstack_free(&cppflags_obst, NULL);
diff --git a/mangle.c b/mangle.c
index 2ac2287..da43b1a 100644
--- a/mangle.c
+++ b/mangle.c
@@ -56,7 +56,7 @@ static char get_atomic_type_mangle(atomic_type_kind_t kind)
case ATOMIC_TYPE_FLOAT: return 'f';
case ATOMIC_TYPE_DOUBLE: return 'd';
}
- panic("invalid atomic type in mangler");
+ panic("invalid atomic type");
}
static void mangle_atomic_type(const atomic_type_t *type)
diff --git a/parser.c b/parser.c
index 128b7f2..76343b5 100644
--- a/parser.c
+++ b/parser.c
@@ -41,6 +41,7 @@
#include "walk.h"
#include "warning.h"
#include "printer.h"
+#include "ast2firm.h"
#include "adt/bitfiddle.h"
#include "adt/error.h"
#include "adt/array.h"
@@ -132,7 +133,7 @@ static elf_visibility_tag_t default_visibility = ELF_VISIBILITY_DEFAULT;
#define PUSH_EXTENSION() \
(void)0; \
bool const old_gcc_extension = in_gcc_extension; \
- while (next_if(T___extension__)) { \
+ while (accept(T___extension__)) { \
in_gcc_extension = true; \
} \
do {} while (0)
@@ -322,6 +323,7 @@ static size_t get_expression_struct_size(expression_kind_t kind)
[EXPR_LITERAL_INTEGER] = sizeof(literal_expression_t),
[EXPR_LITERAL_FLOATINGPOINT] = sizeof(literal_expression_t),
[EXPR_LITERAL_CHARACTER] = sizeof(string_literal_expression_t),
+ [EXPR_LITERAL_MS_NOOP] = sizeof(literal_expression_t),
[EXPR_STRING_LITERAL] = sizeof(string_literal_expression_t),
[EXPR_COMPOUND_LITERAL] = sizeof(compound_literal_expression_t),
[EXPR_CALL] = sizeof(call_expression_t),
@@ -484,7 +486,13 @@ static inline void eat(token_kind_t const kind)
next_token();
}
-static inline bool next_if(token_kind_t const kind)
+/**
+ * Consume the current token, if it is of the expected kind.
+ *
+ * @param kind The kind of token to consume.
+ * @return Whether the token was consumed.
+ */
+static inline bool accept(token_kind_t const kind)
{
if (token.kind == kind) {
eat(kind);
@@ -595,7 +603,7 @@ static void eat_until_anchor(void)
static void eat_block(void)
{
eat_until_matching_token('{');
- next_if('}');
+ accept('}');
}
/**
@@ -1058,8 +1066,13 @@ static string_t concat_string_literals(void)
warningf(WARN_TRADITIONAL, HERE, "traditional C rejects string constant concatenation");
string_encoding_t enc = token.literal.string.encoding;
do {
- if (token.literal.string.encoding != STRING_ENCODING_CHAR) {
- enc = token.literal.string.encoding;
+ string_encoding_t const new_enc = token.literal.string.encoding;
+ if (new_enc != enc && new_enc != STRING_ENCODING_CHAR) {
+ if (enc == STRING_ENCODING_CHAR) {
+ enc = new_enc;
+ } else {
+ errorf(HERE, "concatenating string literals with encodings %s and %s", get_string_encoding_prefix(enc), get_string_encoding_prefix(new_enc));
+ }
}
append_string(&token.literal.string);
eat(T_STRING_LITERAL);
@@ -1082,7 +1095,7 @@ static string_t parse_string_literals(char const *const context)
string_t const res = concat_string_literals();
if (res.encoding != STRING_ENCODING_CHAR) {
- errorf(&pos, "expected plain string literal, got wide string literal");
+ errorf(&pos, "expected plain string literal, got %s string literal", get_string_encoding_prefix(res.encoding));
}
return res;
@@ -1148,7 +1161,7 @@ static attribute_argument_t *parse_attribute_arguments(void)
/* append argument */
*anchor = argument;
anchor = &argument->next;
- } while (next_if(','));
+ } while (accept(','));
expect(')');
return first;
}
@@ -1196,7 +1209,7 @@ static attribute_t *parse_attribute_gnu_single(void)
next_token();
/* parse arguments */
- if (next_if('('))
+ if (accept('('))
attribute->a.arguments = parse_attribute_arguments();
return attribute;
@@ -1219,7 +1232,7 @@ static attribute_t *parse_attribute_gnu(void)
*anchor = attribute;
anchor = &attribute->next;
}
- } while (next_if(','));
+ } while (accept(','));
rem_anchor_token(',');
rem_anchor_token(')');
@@ -1563,7 +1576,8 @@ static initializer_t *initializer_from_expression(type_t *orig_type,
array_type_t *const array_type = &type->array;
type_t *const element_type = skip_typeref(array_type->element_type);
switch (expression->string_literal.value.encoding) {
- case STRING_ENCODING_CHAR: {
+ case STRING_ENCODING_CHAR:
+ case STRING_ENCODING_UTF8: {
if (is_type_atomic(element_type, ATOMIC_TYPE_CHAR) ||
is_type_atomic(element_type, ATOMIC_TYPE_SCHAR) ||
is_type_atomic(element_type, ATOMIC_TYPE_UCHAR)) {
@@ -1572,9 +1586,12 @@ static initializer_t *initializer_from_expression(type_t *orig_type,
break;
}
+ case STRING_ENCODING_CHAR16:
+ case STRING_ENCODING_CHAR32:
case STRING_ENCODING_WIDE: {
- type_t *bare_wchar_type = skip_typeref(type_wchar_t);
- if (get_unqualified_type(element_type) == bare_wchar_type) {
+ assert(is_type_pointer(expression->base.type));
+ type_t *const init_type = get_unqualified_type(expression->base.type->pointer.points_to);
+ if (types_compatible(get_unqualified_type(element_type), init_type)) {
make_string_init:;
initializer_t *const init = allocate_initializer_zero(INITIALIZER_STRING);
init->value.value = expression;
@@ -1635,7 +1652,7 @@ static initializer_t *parse_scalar_initializer(type_t *type,
bool additional_warning_displayed = false;
while (braces > 0) {
- next_if(',');
+ accept(',');
if (token.kind != '}') {
if (!additional_warning_displayed) {
warningf(WARN_OTHER, HERE, "additional elements in scalar initializer");
@@ -1927,7 +1944,7 @@ static void advance_current_object(type_path_t *path, size_t top_path_level)
*/
static void skip_initializers(void)
{
- next_if('{');
+ accept('{');
while (token.kind != '}') {
if (token.kind == T_EOF)
@@ -2066,7 +2083,7 @@ finish_designator:
if (expression->kind == EXPR_STRING_LITERAL && outer_type != NULL) {
result = initializer_from_expression(outer_type, expression);
if (result != NULL) {
- next_if(',');
+ accept(',');
if (token.kind != '}') {
warningf(WARN_OTHER, HERE, "excessive elements in initializer for type '%T'", outer_type);
}
@@ -2112,7 +2129,7 @@ finish_designator:
ARR_APP1(initializer_t*, initializers, sub);
error_parse_next:
- if (!next_if(','))
+ if (!accept(','))
break;
if (token.kind == '}') {
break;
@@ -2334,7 +2351,7 @@ static void parse_enum_entries(type_t *const enum_type)
entity->enum_value.enum_type = enum_type;
rem_anchor_token('=');
- if (next_if('=')) {
+ if (accept('=')) {
expression_t *value = parse_constant_expression();
value = create_implicit_cast(value, enum_type);
@@ -2344,7 +2361,7 @@ static void parse_enum_entries(type_t *const enum_type)
}
record_entity(entity, false);
- } while (next_if(',') && token.kind != '}');
+ } while (accept(',') && token.kind != '}');
rem_anchor_token(',');
rem_anchor_token('}');
@@ -2529,7 +2546,7 @@ static attribute_t *parse_attribute_ms_property(attribute_t *attribute)
symbol_t *const sym = expect_identifier("while parsing property declspec", NULL);
if (prop != NULL)
*prop = sym ? sym : sym_anonymous;
- } while (next_if(','));
+ } while (accept(','));
rem_anchor_token(',');
rem_anchor_token(')');
@@ -2542,7 +2559,7 @@ static attribute_t *parse_attribute_ms_property(attribute_t *attribute)
static attribute_t *parse_microsoft_extended_decl_modifier_single(void)
{
attribute_kind_t kind = ATTRIBUTE_UNKNOWN;
- if (next_if(T_restrict)) {
+ if (accept(T_restrict)) {
kind = ATTRIBUTE_MS_RESTRICT;
} else if (token.kind == T_IDENTIFIER) {
char const *const name = token.base.symbol->string;
@@ -2571,7 +2588,7 @@ static attribute_t *parse_microsoft_extended_decl_modifier_single(void)
}
/* parse arguments */
- if (next_if('('))
+ if (accept('('))
attribute->a.arguments = parse_attribute_arguments();
return attribute;
@@ -2596,7 +2613,7 @@ static attribute_t *parse_microsoft_extended_decl_modifier(attribute_t *first)
*anchor = attribute;
anchor = &attribute->next;
- } while (next_if(','));
+ } while (accept(','));
}
rem_anchor_token(')');
expect(')');
@@ -3070,7 +3087,7 @@ static void parse_identifier_list(scope_t *scope)
if (scope != NULL)
append_entity(scope, entity);
- } while (next_if(',') && token.kind == T_IDENTIFIER);
+ } while (accept(',') && token.kind == T_IDENTIFIER);
}
static entity_t *parse_parameter(void)
@@ -3183,7 +3200,7 @@ static void parse_parameters(function_type_t *type, scope_t *scope)
default:
goto parameters_finished;
}
- } while (next_if(','));
+ } while (accept(','));
parameters_finished:
rem_anchor_token(',');
}
@@ -3280,12 +3297,12 @@ static construct_type_t *parse_array_declarator(void)
eat('[');
add_anchor_token(']');
- bool is_static = next_if(T_static);
+ bool is_static = accept(T_static);
type_qualifiers_t type_qualifiers = parse_type_qualifiers();
if (!is_static)
- is_static = next_if(T_static);
+ is_static = accept(T_static);
array->type_qualifiers = type_qualifiers;
array->is_static = is_static;
@@ -4281,7 +4298,7 @@ static void parse_declaration_rest(entity_t *ndeclaration,
check_variable_type_complete(entity);
- if (!next_if(','))
+ if (!accept(','))
break;
add_anchor_token('=');
@@ -4571,8 +4588,7 @@ static void check_declarations(void)
warn_unused_entity(WARN_UNUSED_PARAMETER, scope->entities, NULL);
}
if (is_warn_on(WARN_UNUSED_VARIABLE)) {
- walk_statements(current_function->statement, check_unused_variables,
- NULL);
+ walk_statements(current_function->body, check_unused_variables, NULL);
}
}
@@ -4789,7 +4805,7 @@ static void check_reachable(statement_t *const stmt)
return;
if (is_constant_expression(expr) == EXPR_CLASS_CONSTANT) {
- long const val = fold_constant_to_int(expr);
+ ir_tarval *const val = fold_constant_to_tarval(expr);
case_label_statement_t * defaults = NULL;
for (case_label_statement_t *i = switchs->first_case; i != NULL; i = i->next) {
if (i->expression == NULL) {
@@ -4797,7 +4813,9 @@ static void check_reachable(statement_t *const stmt)
continue;
}
- if (i->first_case <= val && val <= i->last_case) {
+ if (i->first_case == val || i->last_case == val ||
+ ((tarval_cmp(i->first_case, val) & ir_relation_less_equal)
+ && (tarval_cmp(val, i->last_case) & ir_relation_less_equal))) {
check_reachable((statement_t*)i);
return;
}
@@ -5267,7 +5285,7 @@ static void parse_external_declaration(void)
environment_push(parameter);
}
- if (function->statement != NULL) {
+ if (function->body != NULL) {
parser_error_multiple_definition(entity, HERE);
eat_block();
} else {
@@ -5284,7 +5302,7 @@ static void parse_external_declaration(void)
label_anchor = &label_first;
statement_t *const body = parse_compound_statement(false);
- function->statement = body;
+ function->body = body;
first_err = true;
check_labels();
check_declarations();
@@ -5558,7 +5576,7 @@ static void parse_compound_declarators(compound_t *compound,
append_entity(&compound->members, entity);
}
}
- } while (next_if(','));
+ } while (accept(','));
rem_anchor_token(',');
rem_anchor_token(';');
expect(';');
@@ -5630,8 +5648,11 @@ static type_t *get_string_type(string_encoding_t const enc)
{
bool const warn = is_warn_on(WARN_WRITE_STRINGS);
switch (enc) {
- case STRING_ENCODING_CHAR: return warn ? type_const_char_ptr : type_char_ptr;
- case STRING_ENCODING_WIDE: return warn ? type_const_wchar_t_ptr : type_wchar_t_ptr;
+ case STRING_ENCODING_CHAR:
+ case STRING_ENCODING_UTF8: return warn ? type_const_char_ptr : type_char_ptr;
+ case STRING_ENCODING_CHAR16: return warn ? type_char16_t_const_ptr : type_char16_t_ptr;
+ case STRING_ENCODING_CHAR32: return warn ? type_char32_t_const_ptr : type_char32_t_ptr;
+ case STRING_ENCODING_WIDE: return warn ? type_const_wchar_t_ptr : type_wchar_t_ptr;
}
panic("invalid string encoding");
}
@@ -5872,6 +5893,7 @@ static expression_t *parse_character_constant(void)
size_t const size = get_string_len(&token.literal.string);
switch (token.literal.string.encoding) {
case STRING_ENCODING_CHAR:
+ case STRING_ENCODING_UTF8:
literal->base.type = c_mode & _CXX ? type_char : type_int;
if (size > 1) {
if (!GNU_MODE && !(c_mode & _C99)) {
@@ -5883,8 +5905,10 @@ static expression_t *parse_character_constant(void)
}
break;
- case STRING_ENCODING_WIDE:
- literal->base.type = type_int;
+ case STRING_ENCODING_CHAR16: literal->base.type = type_char16_t; goto warn_multi;
+ case STRING_ENCODING_CHAR32: literal->base.type = type_char32_t; goto warn_multi;
+ case STRING_ENCODING_WIDE: literal->base.type = type_wchar_t; goto warn_multi;
+warn_multi:
if (size > 1) {
warningf(WARN_MULTICHAR, HERE, "multi-character character constant");
}
@@ -6024,7 +6048,7 @@ static entity_t *parse_qualified_identifier(void)
source_position_t pos;
const scope_t *lookup_scope = NULL;
- if (next_if(T_COLONCOLON))
+ if (accept(T_COLONCOLON))
lookup_scope = &unit->scope;
entity_t *entity;
@@ -6036,7 +6060,7 @@ static entity_t *parse_qualified_identifier(void)
/* lookup entity */
entity = lookup_entity(lookup_scope, symbol, NAMESPACE_NORMAL);
- if (!next_if(T_COLONCOLON))
+ if (!accept(T_COLONCOLON))
break;
switch (entity->kind) {
@@ -6053,7 +6077,7 @@ static entity_t *parse_qualified_identifier(void)
symbol, get_entity_kind_name(entity->kind));
/* skip further qualifications */
- while (next_if(T_IDENTIFIER) && next_if(T_COLONCOLON)) {}
+ while (accept(T_IDENTIFIER) && accept(T_COLONCOLON)) {}
return create_error_entity(sym_anonymous, ENTITY_VARIABLE);
}
@@ -6302,7 +6326,7 @@ static designator_t *parse_designator(void)
designator_t *last_designator = result;
while (true) {
- if (next_if('.')) {
+ if (accept('.')) {
designator_t *const designator = allocate_ast_zero(sizeof(result[0]));
designator->symbol = expect_identifier("while parsing member designator", &designator->source_position);
if (!designator->symbol)
@@ -6312,7 +6336,7 @@ static designator_t *parse_designator(void)
last_designator = designator;
continue;
}
- if (next_if('[')) {
+ if (accept('[')) {
add_anchor_token(']');
designator_t *designator = allocate_ast_zero(sizeof(result[0]));
designator->source_position = *HERE;
@@ -6656,7 +6680,7 @@ static expression_t *parse_noop_expression(void)
if (token.kind != ')') do {
(void)parse_assignment_expression();
- } while (next_if(','));
+ } while (accept(','));
rem_anchor_token(',');
rem_anchor_token(')');
@@ -6760,7 +6784,8 @@ static expression_t *parse_array_expression(expression_t *left)
check_idx:
res_type = automatic_type_conversion(res_type);
if (!is_type_integer(idx_type)) {
- errorf(&idx->base.source_position, "array subscript must have integer type");
+ if (is_type_valid(idx_type))
+ errorf(&idx->base.source_position, "array subscript must have integer type");
} else if (is_type_atomic(idx_type, ATOMIC_TYPE_CHAR)) {
source_position_t const *const pos = &idx->base.source_position;
warningf(WARN_CHAR_SUBSCRIPTS, pos, "array subscript has char type");
@@ -7022,7 +7047,6 @@ static void handle_builtin_argument_restrictions(call_expression_t *call)
"third argument of '%Y' must be a constant expression",
call->function->reference.entity->base.symbol);
}
- locality = rw->next;
}
break;
default:
@@ -7088,7 +7112,7 @@ static expression_t *parse_call_expression(expression_t *expression)
*anchor = argument;
anchor = &argument->next;
- } while (next_if(','));
+ } while (accept(','));
}
rem_anchor_token(',');
rem_anchor_token(')');
@@ -7371,7 +7395,7 @@ static expression_t *parse_delete(void)
eat(T_delete);
- if (next_if('[')) {
+ if (accept('[')) {
result->kind = EXPR_UNARY_DELETE_ARRAY;
expect(']');
}
@@ -8614,120 +8638,131 @@ static void init_expression_parsers(void)
/**
* Parse a asm statement arguments specification.
*/
-static asm_argument_t *parse_asm_arguments(bool is_out)
+static void parse_asm_arguments(asm_argument_t **anchor, bool const is_out)
{
- asm_argument_t *result = NULL;
- asm_argument_t **anchor = &result;
-
- while (token.kind == T_STRING_LITERAL || token.kind == '[') {
- asm_argument_t *argument = allocate_ast_zero(sizeof(argument[0]));
+ if (token.kind == T_STRING_LITERAL || token.kind == '[') {
+ add_anchor_token(',');
+ do {
+ asm_argument_t *argument = allocate_ast_zero(sizeof(argument[0]));
- if (next_if('[')) {
- add_anchor_token(']');
- argument->symbol = expect_identifier("while parsing asm argument", NULL);
- rem_anchor_token(']');
- expect(']');
- if (!argument->symbol)
- return NULL;
- }
+ add_anchor_token(')');
+ add_anchor_token('(');
+ add_anchor_token(T_STRING_LITERAL);
- argument->constraints = parse_string_literals("asm argument");
- add_anchor_token(')');
- expect('(');
- expression_t *expression = parse_expression();
- rem_anchor_token(')');
- if (is_out) {
- /* Ugly GCC stuff: Allow lvalue casts. Skip casts, when they do not
- * change size or type representation (e.g. int -> long is ok, but
- * int -> float is not) */
- if (expression->kind == EXPR_UNARY_CAST) {
- type_t *const type = expression->base.type;
- type_kind_t const kind = type->kind;
- if (kind == TYPE_ATOMIC || kind == TYPE_POINTER) {
- unsigned flags;
- unsigned size;
- if (kind == TYPE_ATOMIC) {
- atomic_type_kind_t const akind = type->atomic.akind;
- flags = get_atomic_type_flags(akind) & ~ATOMIC_TYPE_FLAG_SIGNED;
- size = get_atomic_type_size(akind);
- } else {
- flags = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC;
- size = get_type_size(type_void_ptr);
- }
+ if (accept('[')) {
+ add_anchor_token(']');
+ argument->symbol = expect_identifier("while parsing asm argument", NULL);
+ rem_anchor_token(']');
+ expect(']');
+ }
- do {
- expression_t *const value = expression->unary.value;
- type_t *const value_type = value->base.type;
- type_kind_t const value_kind = value_type->kind;
-
- unsigned value_flags;
- unsigned value_size;
- if (value_kind == TYPE_ATOMIC) {
- atomic_type_kind_t const value_akind = value_type->atomic.akind;
- value_flags = get_atomic_type_flags(value_akind) & ~ATOMIC_TYPE_FLAG_SIGNED;
- value_size = get_atomic_type_size(value_akind);
- } else if (value_kind == TYPE_POINTER) {
- value_flags = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC;
- value_size = get_type_size(type_void_ptr);
+ rem_anchor_token(T_STRING_LITERAL);
+ argument->constraints = parse_string_literals("asm argument");
+ rem_anchor_token('(');
+ expect('(');
+ expression_t *expression = parse_expression();
+ if (is_out) {
+ /* Ugly GCC stuff: Allow lvalue casts. Skip casts, when they do not
+ * change size or type representation (e.g. int -> long is ok, but
+ * int -> float is not) */
+ if (expression->kind == EXPR_UNARY_CAST) {
+ type_t *const type = expression->base.type;
+ type_kind_t const kind = type->kind;
+ if (kind == TYPE_ATOMIC || kind == TYPE_POINTER) {
+ unsigned flags;
+ unsigned size;
+ if (kind == TYPE_ATOMIC) {
+ atomic_type_kind_t const akind = type->atomic.akind;
+ flags = get_atomic_type_flags(akind) & ~ATOMIC_TYPE_FLAG_SIGNED;
+ size = get_atomic_type_size(akind);
} else {
- break;
+ flags = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC;
+ size = get_type_size(type_void_ptr);
}
- if (value_flags != flags || value_size != size)
- break;
+ do {
+ expression_t *const value = expression->unary.value;
+ type_t *const value_type = value->base.type;
+ type_kind_t const value_kind = value_type->kind;
+
+ unsigned value_flags;
+ unsigned value_size;
+ if (value_kind == TYPE_ATOMIC) {
+ atomic_type_kind_t const value_akind = value_type->atomic.akind;
+ value_flags = get_atomic_type_flags(value_akind) & ~ATOMIC_TYPE_FLAG_SIGNED;
+ value_size = get_atomic_type_size(value_akind);
+ } else if (value_kind == TYPE_POINTER) {
+ value_flags = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC;
+ value_size = get_type_size(type_void_ptr);
+ } else {
+ break;
+ }
+
+ if (value_flags != flags || value_size != size)
+ break;
- expression = value;
- } while (expression->kind == EXPR_UNARY_CAST);
+ expression = value;
+ } while (expression->kind == EXPR_UNARY_CAST);
+ }
}
- }
- if (!is_lvalue(expression)) {
- errorf(&expression->base.source_position,
- "asm output argument is not an lvalue");
- }
+ if (!is_lvalue(expression))
+ errorf(&expression->base.source_position, "asm output argument is not an lvalue");
- if (argument->constraints.begin[0] == '=')
- determine_lhs_ent(expression, NULL);
- else
+ if (argument->constraints.begin[0] == '=')
+ determine_lhs_ent(expression, NULL);
+ else
+ mark_vars_read(expression, NULL);
+ } else {
mark_vars_read(expression, NULL);
- } else {
- mark_vars_read(expression, NULL);
- }
- argument->expression = expression;
- expect(')');
-
- set_address_taken(expression, true);
+ }
+ argument->expression = expression;
+ rem_anchor_token(')');
+ expect(')');
- *anchor = argument;
- anchor = &argument->next;
+ set_address_taken(expression, true);
- if (!next_if(','))
- break;
+ *anchor = argument;
+ anchor = &argument->next;
+ } while (accept(','));
+ rem_anchor_token(',');
}
-
- return result;
}
/**
* Parse a asm statement clobber specification.
*/
-static asm_clobber_t *parse_asm_clobbers(void)
+static void parse_asm_clobbers(asm_clobber_t **anchor)
{
- asm_clobber_t *result = NULL;
- asm_clobber_t **anchor = &result;
+ if (token.kind == T_STRING_LITERAL) {
+ add_anchor_token(',');
+ do {
+ asm_clobber_t *clobber = allocate_ast_zero(sizeof(clobber[0]));
+ clobber->clobber = parse_string_literals(NULL);
- while (token.kind == T_STRING_LITERAL) {
- asm_clobber_t *clobber = allocate_ast_zero(sizeof(clobber[0]));
- clobber->clobber = parse_string_literals(NULL);
+ *anchor = clobber;
+ anchor = &clobber->next;
+ } while (accept(','));
+ rem_anchor_token(',');
+ }
+}
- *anchor = clobber;
- anchor = &clobber->next;
+static void parse_asm_labels(asm_label_t **anchor)
+{
+ if (token.kind == T_IDENTIFIER) {
+ add_anchor_token(',');
+ do {
+ label_t *const label = get_label("while parsing 'asm goto' labels");
+ if (label) {
+ asm_label_t *const asm_label = allocate_ast_zero(sizeof(*asm_label));
+ asm_label->label = label;
- if (!next_if(','))
- break;
+ *anchor = asm_label;
+ anchor = &asm_label->next;
+ }
+ } while (accept(','));
+ rem_anchor_token(',');
}
-
- return result;
}
/**
@@ -8743,22 +8778,30 @@ static statement_t *parse_asm_statement(void)
add_anchor_token(':');
add_anchor_token(T_STRING_LITERAL);
- if (next_if(T_volatile))
+ if (accept(T_volatile))
asm_statement->is_volatile = true;
+ bool const asm_goto = accept(T_goto);
+
expect('(');
rem_anchor_token(T_STRING_LITERAL);
asm_statement->asm_text = parse_string_literals("asm statement");
- if (next_if(':'))
- asm_statement->outputs = parse_asm_arguments(true);
-
- if (next_if(':'))
- asm_statement->inputs = parse_asm_arguments(false);
+ if (accept(':')) parse_asm_arguments(&asm_statement->outputs, true);
+ if (accept(':')) parse_asm_arguments(&asm_statement->inputs, false);
+ if (accept(':')) parse_asm_clobbers( &asm_statement->clobbers);
rem_anchor_token(':');
- if (next_if(':'))
- asm_statement->clobbers = parse_asm_clobbers();
+ if (accept(':')) {
+ if (!asm_goto)
+ warningf(WARN_OTHER, &statement->base.source_position, "assembler statement with labels should be 'asm goto'");
+ parse_asm_labels(&asm_statement->labels);
+ if (asm_statement->labels)
+ errorf(&statement->base.source_position, "'asm goto' not supported");
+ } else {
+ if (asm_goto)
+ warningf(WARN_OTHER, &statement->base.source_position, "'asm goto' without labels");
+ }
rem_anchor_token(')');
expect(')');
@@ -8840,13 +8883,13 @@ static statement_t *parse_case_statement(void)
}
statement->case_label.is_bad = true;
} else {
- long const val = fold_constant_to_int(expression);
+ ir_tarval *val = fold_constant_to_tarval(expression);
statement->case_label.first_case = val;
statement->case_label.last_case = val;
}
if (GNU_MODE) {
- if (next_if(T_DOTDOTDOT)) {
+ if (accept(T_DOTDOTDOT)) {
expression_t *end_range = parse_expression();
expression_type = expression->base.type;
skipped = skip_typeref(expression_type);
@@ -8864,10 +8907,11 @@ static statement_t *parse_case_statement(void)
}
statement->case_label.is_bad = true;
} else {
- long const val = fold_constant_to_int(end_range);
+ ir_tarval *val = fold_constant_to_tarval(end_range);
statement->case_label.last_case = val;
- if (val < statement->case_label.first_case) {
+ if (tarval_cmp(val, statement->case_label.first_case)
+ == ir_relation_less) {
statement->case_label.is_empty_range = true;
warningf(WARN_OTHER, pos, "empty range specified");
}
@@ -8972,6 +9016,7 @@ static statement_t *parse_label_statement(void)
} else {
label->base.source_position = *pos;
label->statement = statement;
+ label->n_users += 1;
}
eat(':');
@@ -9044,7 +9089,7 @@ static statement_t *parse_if(void)
"suggest braces around empty body in an ‘if’ statement");
}
- if (next_if(T_else)) {
+ if (accept(T_else)) {
statement->ifs.false_statement = parse_inner_statement();
if (statement->ifs.false_statement->kind == STATEMENT_EMPTY) {
@@ -9071,28 +9116,32 @@ static void check_enum_cases(const switch_statement_t *statement)
{
if (!is_warn_on(WARN_SWITCH_ENUM))
return;
- const type_t *type = skip_typeref(statement->expression->base.type);
+ type_t *type = skip_typeref(statement->expression->base.type);
if (! is_type_enum(type))
return;
- const enum_type_t *enumt = &type->enumt;
+ enum_type_t *enumt = &type->enumt;
/* if we have a default, no warnings */
if (statement->default_label != NULL)
return;
+ determine_enum_values(enumt);
+
/* FIXME: calculation of value should be done while parsing */
/* TODO: quadratic algorithm here. Change to an n log n one */
- long last_value = -1;
- const entity_t *entry = enumt->enume->base.next;
+ const entity_t *entry = enumt->enume->base.next;
for (; entry != NULL && entry->kind == ENTITY_ENUM_VALUE;
entry = entry->base.next) {
- const expression_t *expression = entry->enum_value.value;
- long value = expression != NULL ? fold_constant_to_int(expression) : last_value + 1;
- bool found = false;
- for (const case_label_statement_t *l = statement->first_case; l != NULL; l = l->next) {
+ ir_tarval *value = entry->enum_value.tv;
+ bool found = false;
+ for (const case_label_statement_t *l = statement->first_case; l != NULL;
+ l = l->next) {
if (l->expression == NULL)
continue;
- if (l->first_case <= value && value <= l->last_case) {
+ if (l->first_case == l->last_case && l->first_case != value)
+ continue;
+ if ((tarval_cmp(l->first_case, value) & ir_relation_less_equal)
+ && (tarval_cmp(value, l->last_case) & ir_relation_less_equal)) {
found = true;
break;
}
@@ -9101,7 +9150,6 @@ static void check_enum_cases(const switch_statement_t *statement)
source_position_t const *const pos = &statement->base.source_position;
warningf(WARN_SWITCH_ENUM, pos, "'%N' not handled in switch", entry);
}
- last_value = value;
}
}
@@ -9228,7 +9276,7 @@ static statement_t *parse_for(void)
PUSH_EXTENSION();
- if (next_if(';')) {
+ if (accept(';')) {
} else if (is_declaration_specifier(&token)) {
parse_declaration(record_entity, DECL_FLAGS_NONE);
} else {
@@ -9308,6 +9356,7 @@ static statement_t *parse_goto(void)
label_t *const label = get_label("while parsing goto");
if (label) {
+ label->n_users += 1;
label->used = true;
statement->gotos.label = label;
@@ -9525,7 +9574,7 @@ static statement_t *parse_ms_try_statment(void)
POP_PARENT();
- if (next_if(T___except)) {
+ if (accept(T___except)) {
expression_t *const expr = parse_condition();
type_t * type = skip_typeref(expr->base.type);
if (is_type_integer(type)) {
@@ -9536,7 +9585,7 @@ static statement_t *parse_ms_try_statment(void)
type = type_error_type;
}
statement->ms_try.except_expression = create_implicit_cast(expr, type);
- } else if (!next_if(T__finally)) {
+ } else if (!accept(T__finally)) {
parse_error_expected("while parsing __try statement", T___except, T___finally, NULL);
}
statement->ms_try.final_statement = parse_compound_statement(false);
@@ -9581,7 +9630,7 @@ static statement_t *parse_local_label_declaration(void)
environment_push(entity);
}
}
- } while (next_if(','));
+ } while (accept(','));
rem_anchor_token(',');
rem_anchor_token(';');
expect(';');
@@ -9995,7 +10044,7 @@ static void check_unused_globals(void)
continue;
why = WARN_UNUSED_FUNCTION;
- s = entity->function.statement != NULL ? "defined" : "declared";
+ s = entity->function.body != NULL ? "defined" : "declared";
} else {
why = WARN_UNUSED_VARIABLE;
s = "defined";
@@ -10045,7 +10094,7 @@ static void parse_linkage_specification(void)
}
current_linkage = new_linkage;
- if (next_if('{')) {
+ if (accept('{')) {
parse_externals();
expect('}');
} else {
@@ -10231,7 +10280,7 @@ static void complete_incomplete_arrays(void)
static void prepare_main_collect2(entity_t *const entity)
{
- PUSH_SCOPE(&entity->function.statement->compound.scope);
+ PUSH_SCOPE(&entity->function.body->compound.scope);
// create call to __main
symbol_t *symbol = symbol_table_insert("__main");
@@ -10253,9 +10302,9 @@ static void prepare_main_collect2(entity_t *const entity)
expr_statement->base.source_position = builtin_source_position;
expr_statement->expression.expression = call;
- statement_t *statement = entity->function.statement;
- assert(statement->kind == STATEMENT_COMPOUND);
- compound_statement_t *compounds = &statement->compound;
+ statement_t *const body = entity->function.body;
+ assert(body->kind == STATEMENT_COMPOUND);
+ compound_statement_t *compounds = &body->compound;
expr_statement->base.next = compounds->statements;
compounds->statements = expr_statement;
diff --git a/preprocessor.c b/preprocessor.c
index 6e3daf3..74b8277 100644
--- a/preprocessor.c
+++ b/preprocessor.c
@@ -136,6 +136,11 @@ static symbol_t *symbol_percentcolon;
static symbol_t *symbol_percentcolonpercentcolon;
static symbol_t *symbol_percentgreater;
+static symbol_t *symbol_L;
+static symbol_t *symbol_U;
+static symbol_t *symbol_u;
+static symbol_t *symbol_u8;
+
static void init_symbols(void)
{
symbol_colongreater = symbol_table_insert(":>");
@@ -144,6 +149,11 @@ static void init_symbols(void)
symbol_percentcolon = symbol_table_insert("%:");
symbol_percentcolonpercentcolon = symbol_table_insert("%:%:");
symbol_percentgreater = symbol_table_insert("%>");
+
+ symbol_L = symbol_table_insert("L");
+ symbol_U = symbol_table_insert("U");
+ symbol_u = symbol_table_insert("u");
+ symbol_u8 = symbol_table_insert("u8");
}
void switch_pp_input(FILE *const file, char const *const filename, searchpath_entry_t *const path, bool const is_system_header)
@@ -684,6 +694,18 @@ string_t make_string(char const *const string)
return sym_make_string(STRING_ENCODING_CHAR);
}
+static utf32 get_string_encoding_limit(string_encoding_t const enc)
+{
+ switch (enc) {
+ case STRING_ENCODING_CHAR: return 0xFF;
+ case STRING_ENCODING_CHAR16: return 0xFFFF;
+ case STRING_ENCODING_CHAR32: return 0xFFFFFFFF;
+ case STRING_ENCODING_UTF8: return 0xFFFFFFFF;
+ case STRING_ENCODING_WIDE: return 0xFFFFFFFF; // FIXME depends on settings
+ }
+ panic("invalid string encoding");
+}
+
static void parse_string(utf32 const delimiter, token_kind_t const kind,
string_encoding_t const enc,
char const *const context)
@@ -692,15 +714,16 @@ static void parse_string(utf32 const delimiter, token_kind_t const kind,
eat(delimiter);
+ utf32 const limit = get_string_encoding_limit(enc);
while (true) {
switch (input.c) {
case '\\': {
if (resolve_escape_sequences) {
utf32 const tc = parse_escape_sequence();
+ if (tc > limit) {
+ warningf(WARN_OTHER, &pp_token.base.source_position, "escape sequence out of range");
+ }
if (enc == STRING_ENCODING_CHAR) {
- if (tc >= 0x100) {
- warningf(WARN_OTHER, &pp_token.base.source_position, "escape sequence out of range");
- }
obstack_1grow(&symbol_obstack, tc);
} else {
obstack_grow_utf8(&symbol_obstack, tc);
@@ -1133,6 +1156,17 @@ static inline void eat_token(token_kind_t const kind)
next_input_token();
}
+static string_encoding_t identify_encoding_prefix(symbol_t *const sym)
+{
+ if (sym == symbol_L) return STRING_ENCODING_WIDE;
+ if (c_mode & _C11) {
+ if (sym == symbol_U) return STRING_ENCODING_CHAR32;
+ if (sym == symbol_u) return STRING_ENCODING_CHAR16;
+ if (sym == symbol_u8) return STRING_ENCODING_UTF8;
+ }
+ return STRING_ENCODING_CHAR;
+}
+
static void parse_symbol(void)
{
assert(obstack_object_size(&symbol_obstack) == 0);
@@ -1190,19 +1224,26 @@ end_symbol:
obstack_1grow(&symbol_obstack, '\0');
char *string = obstack_finish(&symbol_obstack);
- /* might be a wide string or character constant ( L"string"/L'c' ) */
- if (input.c == '"' && string[0] == 'L' && string[1] == '\0') {
- obstack_free(&symbol_obstack, string);
- parse_string_literal(STRING_ENCODING_WIDE);
- return;
- } else if (input.c == '\'' && string[0] == 'L' && string[1] == '\0') {
- obstack_free(&symbol_obstack, string);
- parse_character_constant(STRING_ENCODING_WIDE);
- return;
- }
-
symbol_t *symbol = symbol_table_insert(string);
+ /* Might be a prefixed string or character constant: L/U/u/u8"string". */
+ if (input.c == '"') {
+ string_encoding_t const enc = identify_encoding_prefix(symbol);
+ if (enc != STRING_ENCODING_CHAR) {
+ parse_string_literal(enc);
+ return;
+ }
+ } else if (input.c == '\'') {
+ string_encoding_t const enc = identify_encoding_prefix(symbol);
+ if (enc != STRING_ENCODING_CHAR) {
+ if (enc == STRING_ENCODING_UTF8) {
+ errorf(&pp_token.base.source_position, "'u8' is not a valid encoding for a chracter constant");
+ }
+ parse_character_constant(enc);
+ return;
+ }
+ }
+
pp_token.kind = symbol->ID;
pp_token.base.symbol = symbol;
@@ -1491,8 +1532,7 @@ digraph_percentcolon:
default:
dollar_sign:
if (error_on_unknown_chars) {
- errorf(&pp_token.base.source_position,
- "unknown character '%lc' found\n", input.c);
+ errorf(&pp_token.base.source_position, "unknown character '%lc' found", input.c);
next_char();
goto restart;
} else {
diff --git a/separator_t.h b/separator_t.h
new file mode 100644
index 0000000..63ee1e6
--- /dev/null
+++ b/separator_t.h
@@ -0,0 +1,31 @@
+#ifndef SEPARATOR_H
+#define SEPARATOR_H
+
+#include <stdbool.h>
+
+typedef struct separator_t separator_t;
+struct separator_t
+{
+ char const *first; /**< Returned on the first call to sep_next(). */
+ char const *rest; /**< Returned on all further calls to sep_next(). */
+};
+
+/**
+ * Returns first on the first call for s and rest on all further calls.
+ */
+static inline char const* sep_next(separator_t* const s)
+{
+ char const *const cur = s->first;
+ s->first = s->rest;
+ return cur;
+}
+
+/**
+ * Returns whether sep_next() has not been called for s.
+ */
+static inline bool sep_at_first(separator_t const* const s)
+{
+ return s->first != s->rest;
+}
+
+#endif
diff --git a/string_rep.c b/string_rep.c
index ff58aad..28b0746 100644
--- a/string_rep.c
+++ b/string_rep.c
@@ -16,8 +16,11 @@ static inline size_t wstrlen(const string_t *string)
size_t get_string_len(string_t const *const str)
{
switch (str->encoding) {
- case STRING_ENCODING_CHAR: return str->size;
- case STRING_ENCODING_WIDE: return wstrlen(str);
+ case STRING_ENCODING_CHAR:
+ case STRING_ENCODING_UTF8: return str->size;
+ case STRING_ENCODING_CHAR16:
+ case STRING_ENCODING_CHAR32:
+ case STRING_ENCODING_WIDE: return wstrlen(str);
}
panic("invalid string encoding");
}
diff --git a/string_rep.h b/string_rep.h
index c0868eb..ce4ca3e 100644
--- a/string_rep.h
+++ b/string_rep.h
@@ -25,6 +25,9 @@
enum string_encoding_t {
STRING_ENCODING_CHAR,
+ STRING_ENCODING_CHAR16,
+ STRING_ENCODING_CHAR32,
+ STRING_ENCODING_UTF8,
STRING_ENCODING_WIDE
};
typedef enum string_encoding_t string_encoding_t;
diff --git a/token.c b/token.c
index 7d2104c..50de656 100644
--- a/token.c
+++ b/token.c
@@ -95,8 +95,11 @@ void print_token_kind(FILE *f, token_kind_t token_kind)
char const *get_string_encoding_prefix(string_encoding_t const enc)
{
switch (enc) {
- case STRING_ENCODING_CHAR: return "";
- case STRING_ENCODING_WIDE: return "L";
+ case STRING_ENCODING_CHAR: return "";
+ case STRING_ENCODING_CHAR16: return "u";
+ case STRING_ENCODING_CHAR32: return "U";
+ case STRING_ENCODING_UTF8: return "u8";
+ case STRING_ENCODING_WIDE: return "L";
}
panic("invalid string encoding");
}
diff --git a/type.c b/type.c
index 0c697ef..c904c7c 100644
--- a/type.c
+++ b/type.c
@@ -33,6 +33,7 @@
#include "warning.h"
#include "diagnostic.h"
#include "printer.h"
+#include "separator_t.h"
/** The default calling convention. */
cc_kind_t default_calling_convention = CC_CDECL;
@@ -373,15 +374,11 @@ static void print_function_type_post(const function_type_t *type,
const scope_t *parameters)
{
print_char('(');
- bool first = true;
+ separator_t sep = { "", ", " };
if (parameters == NULL) {
function_parameter_t *parameter = type->parameters;
for( ; parameter != NULL; parameter = parameter->next) {
- if (first) {
- first = false;
- } else {
- print_string(", ");
- }
+ print_string(sep_next(&sep));
print_type(parameter->type);
}
} else {
@@ -390,11 +387,7 @@ static void print_function_type_post(const function_type_t *type,
if (parameter->kind != ENTITY_PARAMETER)
continue;
- if (first) {
- first = false;
- } else {
- print_string(", ");
- }
+ print_string(sep_next(&sep));
const type_t *const param_type = parameter->declaration.type;
if (param_type == NULL) {
print_string(parameter->base.symbol->string);
@@ -404,14 +397,10 @@ static void print_function_type_post(const function_type_t *type,
}
}
if (type->variadic) {
- if (first) {
- first = false;
- } else {
- print_string(", ");
- }
+ print_string(sep_next(&sep));
print_string("...");
}
- if (first && !type->unspecified_parameters) {
+ if (sep_at_first(&sep) && !type->unspecified_parameters) {
print_string("void");
}
print_char(')');
@@ -872,10 +861,10 @@ bool is_type_incomplete(const type_t *type)
case TYPE_TYPEDEF:
case TYPE_TYPEOF:
- panic("is_type_incomplete called without typerefs skipped");
+ panic("typedef not skipped");
}
- panic("invalid type found");
+ panic("invalid type");
}
bool is_type_object(const type_t *type)
@@ -1001,7 +990,7 @@ bool types_compatible(const type_t *type1, const type_t *type2)
return true;
case TYPE_TYPEDEF:
case TYPE_TYPEOF:
- panic("typerefs not skipped in compatible types?!?");
+ panic("typeref not skipped");
}
}
@@ -1092,7 +1081,7 @@ unsigned get_type_size(type_t *type)
case TYPE_TYPEOF:
return get_type_size(type->typeoft.typeof_type);
}
- panic("invalid type in get_type_size");
+ panic("invalid type");
}
unsigned get_type_alignment(type_t *type)
@@ -1130,7 +1119,7 @@ unsigned get_type_alignment(type_t *type)
case TYPE_TYPEOF:
return get_type_alignment(type->typeoft.typeof_type);
}
- panic("invalid type in get_type_alignment");
+ panic("invalid type");
}
/**
@@ -1172,7 +1161,7 @@ decl_modifiers_t get_type_modifiers(const type_t *type)
case TYPE_TYPEOF:
return get_type_modifiers(type->typeoft.typeof_type);
}
- panic("invalid type found in get_type_modifiers");
+ panic("invalid type");
}
type_qualifiers_t get_type_qualifier(const type_t *type, bool skip_array_type)
diff --git a/types.c b/types.c
index 24d38d3..d6ff22e 100644
--- a/types.c
+++ b/types.c
@@ -61,6 +61,10 @@ type_t *type_const_void_ptr_restrict;
type_t *type_char_ptr_ptr;
+type_t *type_char16_t;
+type_t *type_char32_t;
+type_t *type_char16_t_const;
+type_t *type_char32_t_const;
type_t *type_intmax_t;
type_t *type_ptrdiff_t;
type_t *type_size_t;
@@ -73,6 +77,10 @@ type_t *type_wint_t;
type_t *type_int32_t;
type_t *type_int64_t;
+type_t *type_char16_t_ptr;
+type_t *type_char32_t_ptr;
+type_t *type_char16_t_const_ptr;
+type_t *type_char32_t_const_ptr;
type_t *type_intmax_t_ptr;
type_t *type_ptrdiff_t_ptr;
type_t *type_ssize_t_ptr;
@@ -198,4 +206,16 @@ void init_wchar_types(atomic_type_kind_t akind)
type_wchar_t_ptr = make_pointer_type(type_wchar_t, TYPE_QUALIFIER_NONE);
type_const_wchar_t_ptr
= make_pointer_type(type_const_wchar_t, TYPE_QUALIFIER_NONE);
+
+ atomic_type_kind_t const u2 = find_unsigned_int_atomic_type_kind_for_size(2);
+ type_char16_t = make_atomic_type(u2, TYPE_QUALIFIER_NONE);
+ type_char16_t_const = make_atomic_type(u2, TYPE_QUALIFIER_CONST);
+ type_char16_t_ptr = make_pointer_type(type_char16_t, TYPE_QUALIFIER_NONE);
+ type_char16_t_const_ptr = make_pointer_type(type_char16_t_const, TYPE_QUALIFIER_NONE);
+
+ atomic_type_kind_t const u4 = find_unsigned_int_atomic_type_kind_for_size(4);
+ type_char32_t = make_atomic_type(u4, TYPE_QUALIFIER_NONE);
+ type_char32_t_const = make_atomic_type(u4, TYPE_QUALIFIER_CONST);
+ type_char32_t_ptr = make_pointer_type(type_char32_t, TYPE_QUALIFIER_NONE);
+ type_char32_t_const_ptr = make_pointer_type(type_char32_t_const, TYPE_QUALIFIER_NONE);
}
diff --git a/types.h b/types.h
index b173a00..e2cc949 100644
--- a/types.h
+++ b/types.h
@@ -60,6 +60,10 @@ extern type_t *type_const_void_ptr_restrict;
extern type_t *type_char_ptr_ptr;
+extern type_t *type_char16_t;
+extern type_t *type_char32_t;
+extern type_t *type_char16_t_const;
+extern type_t *type_char32_t_const;
extern type_t *type_intmax_t;
extern type_t *type_ptrdiff_t;
extern type_t *type_size_t;
@@ -73,6 +77,10 @@ extern type_t *type_wint_t;
extern type_t *type_int32_t;
extern type_t *type_int64_t;
+extern type_t *type_char16_t_ptr;
+extern type_t *type_char32_t_ptr;
+extern type_t *type_char16_t_const_ptr;
+extern type_t *type_char32_t_const_ptr;
extern type_t *type_intmax_t_ptr;
extern type_t *type_ptrdiff_t_ptr;
extern type_t *type_ssize_t_ptr;
diff --git a/walk.c b/walk.c
index 9942903..96a722b 100644
--- a/walk.c
+++ b/walk.c
@@ -83,7 +83,7 @@ static void walk_type(type_t *const type, const walk_env_t *const env)
walk_entity((entity_t*)type->enumt.enume, env);
return;
}
- panic("invalid type found");
+ panic("invalid type");
}
static void walk_expression(expression_t *const expr,
@@ -243,8 +243,8 @@ static void walk_entity(entity_t *entity, const walk_env_t *const env)
return;
case ENTITY_FUNCTION:
walk_type(entity->declaration.type, env);
- if (entity->function.statement != NULL)
- walk_statement(entity->function.statement, env);
+ if (entity->function.body != NULL)
+ walk_statement(entity->function.body, env);
return;
case ENTITY_COMPOUND_MEMBER:
case ENTITY_PARAMETER:
@@ -269,7 +269,7 @@ static void walk_entity(entity_t *entity, const walk_env_t *const env)
case ENTITY_LOCAL_LABEL:
return;
}
- panic("invalid entity found");
+ panic("invalid entity");
}
static void walk_declarations(entity_t* entity,
diff --git a/wrappergen/write_fluffy.c b/wrappergen/write_fluffy.c
index 028adfd..2ea7714 100644
--- a/wrappergen/write_fluffy.c
+++ b/wrappergen/write_fluffy.c
@@ -23,6 +23,7 @@
#include <string.h>
#include "write_fluffy.h"
+#include "separator_t.h"
#include "symbol_t.h"
#include "ast_t.h"
#include "type_t.h"
@@ -127,13 +128,9 @@ static void write_function_type(const function_type_t *type)
fprintf(out, "(func(");
function_parameter_t *parameter = type->parameters;
- int first = 1;
+ separator_t sep = { "", ", " };
while(parameter != NULL) {
- if(!first) {
- fprintf(out, ", ");
- } else {
- first = 0;
- }
+ fputs(sep_next(&sep), out);
#if 0
if(parameter->symbol != NULL) {
@@ -214,7 +211,7 @@ static void write_unary_expression(const unary_expression_t *expression)
fputc('!', out);
break;
default:
- panic("unimeplemented unary expression found");
+ panic("unimplemented unary expression");
}
write_expression(expression->value);
}
@@ -260,7 +257,7 @@ static void write_variable(const entity_t *entity)
static void write_function(const entity_t *entity)
{
- if (entity->function.statement != NULL) {
+ if (entity->function.body != NULL) {
fprintf(stderr, "Warning: can't convert function bodies (at %s)\n",
entity->base.symbol->string);
}
@@ -270,15 +267,11 @@ static void write_function(const entity_t *entity)
const function_type_t *function_type
= (const function_type_t*) entity->declaration.type;
- entity_t *parameter = entity->function.parameters.entities;
- int first = 1;
+ entity_t *parameter = entity->function.parameters.entities;
+ separator_t sep = { "", ", " };
for( ; parameter != NULL; parameter = parameter->base.next) {
assert(parameter->kind == ENTITY_PARAMETER);
- if(!first) {
- fprintf(out, ", ");
- } else {
- first = 0;
- }
+ fputs(sep_next(&sep), out);
if(parameter->base.symbol != NULL) {
fprintf(out, "%s : ", parameter->base.symbol->string);
} else {
@@ -287,11 +280,7 @@ static void write_function(const entity_t *entity)
write_type(parameter->declaration.type);
}
if(function_type->variadic) {
- if(!first) {
- fprintf(out, ", ");
- } else {
- first = 0;
- }
+ fputs(sep_next(&sep), out);
fputs("...", out);
}
fprintf(out, ")");
diff --git a/wrappergen/write_jna.c b/wrappergen/write_jna.c
index ac8b1a1..af9e8bb 100644
--- a/wrappergen/write_jna.c
+++ b/wrappergen/write_jna.c
@@ -33,6 +33,7 @@
#include "adt/error.h"
#include "adt/xmalloc.h"
#include "adt/pset_new.h"
+#include "separator_t.h"
typedef struct output_limit {
const char *filename;
@@ -226,7 +227,7 @@ static void write_type(type_t *type)
case TYPE_ERROR:
case TYPE_TYPEOF:
case TYPE_TYPEDEF:
- panic("invalid type found");
+ panic("invalid type");
case TYPE_ARRAY:
case TYPE_REFERENCE:
case TYPE_FUNCTION:
@@ -275,7 +276,7 @@ static void write_unary_expression(const unary_expression_t *expression)
write_expression(expression->value);
return;
default:
- panic("unimeplemented unary expression found");
+ panic("unimplemented unary expression");
}
write_expression(expression->value);
}
@@ -404,7 +405,7 @@ static void write_variable(const entity_t *entity)
static void write_function(const entity_t *entity)
{
- if (entity->function.statement != NULL) {
+ if (entity->function.body != NULL) {
fprintf(stderr, "Warning: can't convert function bodies (at %s)\n",
entity->base.symbol->string);
return;
@@ -420,16 +421,12 @@ static void write_function(const entity_t *entity)
write_type(return_type);
fprintf(out, " %s(", entity->base.symbol->string);
- entity_t *parameter = entity->function.parameters.entities;
- int first = 1;
- int n = 0;
+ entity_t *parameter = entity->function.parameters.entities;
+ separator_t sep = { "", ", " };
+ int n = 0;
for ( ; parameter != NULL; parameter = parameter->base.next) {
assert(parameter->kind == ENTITY_PARAMETER);
- if(!first) {
- fprintf(out, ", ");
- } else {
- first = 0;
- }
+ fputs(sep_next(&sep), out);
write_type(parameter->declaration.type);
if(parameter->base.symbol != NULL) {
fprintf(out, " %s", fix_builtin_names(parameter->base.symbol->string));
@@ -438,11 +435,7 @@ static void write_function(const entity_t *entity)
}
}
if(function_type->variadic) {
- if(!first) {
- fprintf(out, ", ");
- } else {
- first = 0;
- }
+ fputs(sep_next(&sep), out);
fputs("Object ... args", out);
}
fprintf(out, ");\n");