support for bitfields completed
authorMatthias Braun <matze@braunis.de>
Tue, 11 Dec 2007 11:15:40 +0000 (11:15 +0000)
committerMatthias Braun <matze@braunis.de>
Tue, 11 Dec 2007 11:15:40 +0000 (11:15 +0000)
[r18670]

Makefile
ast.c
ast.h
ast2firm.c
ast_t.h
driver/firm_cmdline.c
driver/firm_cmdline.h
driver/firm_opt.c
lexer.c
main.c
parser.c

index 88c4760..d0f3a6c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -94,4 +94,4 @@ build/%.o: %.c
 
 clean:
        @echo '===> CLEAN'
-       $(Q)rm -rf build $(GOAL) .depend
+       $(Q)rm -rf build/* $(GOAL) .depend
diff --git a/ast.c b/ast.c
index 0687d51..073ab7d 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -204,6 +204,10 @@ static void print_unary_expression(const unary_expression_t *unexpr)
        case EXPR_UNARY_DEREFERENCE:      fputs("*", out);  break;
        case EXPR_UNARY_TAKE_ADDRESS:     fputs("&", out);  break;
 
+       case EXPR_UNARY_BITFIELD_EXTRACT:
+               print_expression(unexpr->value);
+               return;
+
        case EXPR_UNARY_POSTFIX_INCREMENT:
                fputs("(", out);
                print_expression(unexpr->value);
@@ -865,6 +869,7 @@ bool is_constant_expression(const expression_t *expression)
        case EXPR_UNARY_POSTFIX_DECREMENT:
        case EXPR_UNARY_PREFIX_INCREMENT:
        case EXPR_UNARY_PREFIX_DECREMENT:
+       case EXPR_UNARY_BITFIELD_EXTRACT:
        case EXPR_UNARY_ASSUME: /* has VOID type */
        case EXPR_BINARY_ASSIGN:
        case EXPR_BINARY_MUL_ASSIGN:
diff --git a/ast.h b/ast.h
index 0322c76..7fa4490 100644 (file)
--- a/ast.h
+++ b/ast.h
@@ -33,6 +33,7 @@ typedef struct builtin_symbol_expression_t      builtin_symbol_expression_t;
 typedef struct builtin_constant_expression_t    builtin_constant_expression_t;
 typedef struct builtin_prefetch_expression_t    builtin_prefetch_expression_t;
 typedef struct classify_type_expression_t       classify_type_expression_t;
+typedef struct bitfield_extract_expression_t    bitfield_extract_expression_t;
 typedef union  expression_t                     expression_t;
 
 typedef struct initializer_base_t           initializer_base_t;
index 975e292..e8af1ab 100644 (file)
@@ -628,7 +628,7 @@ static ir_type *create_struct_type(compound_type_t *type)
        }
 
        size_t misalign = offset % align_all;
-       if(misalign > 0) {
+       if(misalign > 0 || bit_offset > 0) {
                offset += align_all - misalign;
        }
        set_type_alignment_bytes(irtype, align_all);
@@ -1347,7 +1347,7 @@ static void assign_value(dbg_info *dbgi, ir_node *addr, type_t *type,
 {
        value = do_strict_conv(dbgi, value);
 
-       ir_node  *memory = get_store();
+       ir_node *memory = get_store();
 
        if(is_type_scalar(type)) {
                ir_node  *store     = new_d_Store(dbgi, memory, addr, value);
@@ -1361,6 +1361,71 @@ static void assign_value(dbg_info *dbgi, ir_node *addr, type_t *type,
        }
 }
 
+static tarval *create_bitfield_mask(ir_mode *mode, int offset, int size)
+{
+       tarval *all_one   = get_mode_all_one(mode);
+       int     mode_size = get_mode_size_bits(mode);
+
+       assert(offset >= 0 && size >= 0);
+       assert(offset + size <= mode_size);
+       if(size == mode_size) {
+               return all_one;
+       }
+
+       long    shiftr    = get_mode_size_bits(mode) - size;
+       long    shiftl    = offset;
+       tarval *tv_shiftr = new_tarval_from_long(shiftr, mode_uint);
+       tarval *tv_shiftl = new_tarval_from_long(shiftl, mode_uint);
+       tarval *mask0     = tarval_shr(all_one, tv_shiftr);
+       tarval *mask1     = tarval_shl(mask0, tv_shiftl);
+
+       return mask1;
+}
+
+static void bitfield_store_to_firm(const unary_expression_t *expression,
+                                   ir_node *value)
+{
+       expression_t *select = expression->value;
+       assert(select->kind == EXPR_SELECT);
+       type_t       *type   = select->base.datatype;
+       assert(type->kind == TYPE_BITFIELD);
+       ir_mode      *mode   = get_ir_mode(type->bitfield.base);
+       ir_node      *addr   = expression_to_addr(select);
+
+       assert(get_irn_mode(value) == mode);
+
+       dbg_info *dbgi = get_dbg_info(&expression->expression.source_position);
+
+       /* kill upper bits of value and shift to right position */
+       ir_entity *entity       = select->select.compound_entry->v.entity;
+       int        bitoffset    = get_entity_offset_bits_remainder(entity);
+       ir_type   *entity_type  = get_entity_type(entity);
+       int        bitsize      = get_mode_size_bits(get_type_mode(entity_type));
+
+       tarval  *mask            = create_bitfield_mask(mode, 0, bitsize);
+       ir_node *mask_node       = new_d_Const(dbgi, mode, mask);
+       ir_node *value_masked    = new_d_And(dbgi, value, mask_node, mode);
+       tarval  *shiftl          = new_tarval_from_long(bitoffset, mode_uint);
+       ir_node *shiftcount      = new_d_Const(dbgi, mode_uint, shiftl);
+       ir_node *value_maskshift = new_d_Shl(dbgi, value_masked, shiftcount, mode);
+
+       /* load current value */
+       ir_node  *mem             = get_store();
+       ir_node  *load            = new_d_Load(dbgi, mem, addr, mode);
+       ir_node  *load_mem        = new_d_Proj(dbgi, load, mode_M, pn_Load_M);
+       ir_node  *load_res        = new_d_Proj(dbgi, load, mode, pn_Load_res);
+       tarval   *shift_mask      = create_bitfield_mask(mode, bitoffset, bitsize);
+       tarval   *inv_mask        = tarval_not(shift_mask);
+       ir_node  *inv_mask_node   = new_d_Const(dbgi, mode, inv_mask);
+       ir_node  *load_res_masked = new_d_And(dbgi, load_res, inv_mask_node, mode);
+
+       /* construct new value and store */
+       ir_node *new_val   = new_d_Or(dbgi, load_res_masked, value_maskshift, mode);
+       ir_node *store     = new_d_Store(dbgi, load_mem, addr, new_val);
+       ir_node *store_mem = new_d_Proj(dbgi, store, mode_M, pn_Store_M);
+       set_store(store_mem);
+}
+
 static void set_value_for_expression(const expression_t *expression,
                                      ir_node *value)
 {
@@ -1378,6 +1443,11 @@ static void set_value_for_expression(const expression_t *expression,
                }
        }
 
+       if(expression->kind == EXPR_UNARY_BITFIELD_EXTRACT) {
+               bitfield_store_to_firm(&expression->unary, value);
+               return;
+       }
+
        ir_node *addr = expression_to_addr(expression);
        type_t  *type = skip_typeref(expression->base.datatype);
        assign_value(dbgi, addr, type, value);
@@ -1560,6 +1630,50 @@ static ir_node *handle_assume(dbg_info *dbi, const expression_t *expression) {
        }
 }
 
+static ir_node *bitfield_extract_to_firm(const unary_expression_t *expression)
+{
+       expression_t *select = expression->value;
+       assert(select->kind == EXPR_SELECT);
+
+       type_t   *type     = select->base.datatype;
+       assert(type->kind == TYPE_BITFIELD);
+       ir_mode  *mode     = get_ir_mode(type->bitfield.base);
+       dbg_info *dbgi     = get_dbg_info(&expression->expression.source_position);
+       ir_node  *addr     = expression_to_addr(select);
+       ir_node  *mem      = get_store();
+       ir_node  *load     = new_d_Load(dbgi, mem, addr, mode);
+       ir_node  *load_mem = new_d_Proj(dbgi, load, mode_M, pn_Load_M);
+       ir_node  *load_res = new_d_Proj(dbgi, load, mode, pn_Load_res);
+
+       load_res           = create_conv(dbgi, load_res, mode_int);
+
+       set_store(load_mem);
+
+       /* kill upper bits */
+       ir_entity *entity       = select->select.compound_entry->v.entity;
+       int        bitoffset    = get_entity_offset_bits_remainder(entity);
+       ir_type   *entity_type  = get_entity_type(entity);
+       int        bitsize      = get_mode_size_bits(get_type_mode(entity_type));
+       long       shift_bitsl  = machine_size - bitoffset - bitsize;
+       assert(shift_bitsl >= 0);
+       tarval    *tvl          = new_tarval_from_long(shift_bitsl, mode_uint);
+       ir_node   *countl       = new_d_Const(dbgi, mode_uint, tvl);
+       ir_node   *shiftl       = new_d_Shl(dbgi, load_res, countl, mode_int);
+
+       long       shift_bitsr  = bitoffset + shift_bitsl;
+       assert(shift_bitsr <= (long) machine_size);
+       tarval    *tvr          = new_tarval_from_long(shift_bitsr, mode_uint);
+       ir_node   *countr       = new_d_Const(dbgi, mode_uint, tvr);
+       ir_node   *shiftr;
+       if(mode_is_signed(mode)) {
+               shiftr = new_d_Shrs(dbgi, shiftl, countr, mode_int);
+       } else {
+               shiftr = new_d_Shr(dbgi, shiftl, countr, mode_int);
+       }
+
+       return create_conv(dbgi, shiftr, mode);
+}
+
 static ir_node *unary_expression_to_firm(const unary_expression_t *expression)
 {
        dbg_info *dbgi = get_dbg_info(&expression->expression.source_position);
@@ -1625,6 +1739,8 @@ static ir_node *unary_expression_to_firm(const unary_expression_t *expression)
                        return handle_assume(dbgi, value);
                else
                        return NULL;
+       case EXPR_UNARY_BITFIELD_EXTRACT:
+               return bitfield_extract_to_firm(expression);
 
        default:
                break;
@@ -2330,7 +2446,8 @@ static ir_node *expression_to_addr(const expression_t *expression)
        panic("trying to get address of non-lvalue");
 }
 
-static ir_node *builtin_constant_to_firm(const builtin_constant_expression_t *expression)
+static ir_node *builtin_constant_to_firm(
+               const builtin_constant_expression_t *expression)
 {
        ir_mode *mode = get_ir_mode(expression->expression.datatype);
        long     v;
@@ -2343,7 +2460,8 @@ static ir_node *builtin_constant_to_firm(const builtin_constant_expression_t *ex
        return new_Const_long(mode, v);
 }
 
-static ir_node *builtin_prefetch_to_firm(const builtin_prefetch_expression_t *expression)
+static ir_node *builtin_prefetch_to_firm(
+               const builtin_prefetch_expression_t *expression)
 {
        ir_node *adr = expression_to_firm(expression->adr);
        /* no Firm support for prefetch yet */
diff --git a/ast_t.h b/ast_t.h
index e3039e6..d19147a 100644 (file)
--- a/ast_t.h
+++ b/ast_t.h
@@ -51,7 +51,8 @@ typedef enum {
        EXPR_UNARY_CAST,
        EXPR_UNARY_CAST_IMPLICIT, /**< compiler generated cast */
        EXPR_UNARY_ASSUME,        /**< MS __assume() */
-       EXPR_UNARY_LAST = EXPR_UNARY_ASSUME,
+       EXPR_UNARY_BITFIELD_EXTRACT,
+       EXPR_UNARY_LAST = EXPR_UNARY_BITFIELD_EXTRACT,
 
        EXPR_BINARY_FIRST,
        EXPR_BINARY_ADD = EXPR_BINARY_FIRST,
@@ -148,7 +149,8 @@ typedef enum {
        case EXPR_UNARY_PREFIX_DECREMENT:      \
        case EXPR_UNARY_CAST:                  \
        case EXPR_UNARY_CAST_IMPLICIT:         \
-       case EXPR_UNARY_ASSUME:
+       case EXPR_UNARY_ASSUME:                \
+       case EXPR_UNARY_BITFIELD_EXTRACT:
 
 struct context_t {
        declaration_t *declarations;  /**< List of declarations in this context. */
index df0527e..5bcb2ca 100644 (file)
@@ -59,6 +59,7 @@ struct a_firm_opt firm_opt = {
   /* lower           = */ TRUE,
   /* os_support      = */ OS_SUPPORT_LINUX,
   /* honor_restrict  = */ TRUE,
+  /* lower_bitfields = */ TRUE,
   /* ycomp_dbg       = */ FALSE,
   /* ycomp_host      = */ FIRM_YCOMP_DEFAULT_HOST,
   /* ycomp_port      = */ FIRM_YCOMP_DEFAULT_PORT,
index c16a2c3..9cb0a06 100644 (file)
@@ -72,6 +72,7 @@ struct a_firm_opt {
   a_byte   lower;           /**< enable Firm lowering */
   a_byte   os_support;      /**< current os support */
   a_byte   honor_restrict;  /**< enable restrict keyword */
+  a_byte   lower_bitfields; /**< lower bitfield access */
   a_byte   ycomp_dbg;       /**< yComp debugger extension */
   char     *ycomp_host;     /**< The host, yComp is running on */
   int      ycomp_port;      /**< The port, yComp is listening on */
index e402614..d2c9762 100644 (file)
@@ -464,7 +464,7 @@ static void do_firm_optimizations(const char *input_filename, int firm_const_exi
       CHECK_ONE(firm_opt.check_all, irg);
        }
 
-    lower_highlevel_graph(irg);
+    lower_highlevel_graph(irg, firm_opt.lower_bitfields);
 
     if (firm_opt.deconv) {
       timer_push(TV_DECONV);
diff --git a/lexer.c b/lexer.c
index e8c183c..6a6a945 100644 (file)
--- a/lexer.c
+++ b/lexer.c
@@ -79,7 +79,7 @@ static inline void next_real_char(void)
 static inline void put_back(int pc)
 {
        assert(bufpos > buf);
-       *(--bufpos - buf + buf) = pc;
+       *(--bufpos - buf + buf) = (char) pc;
 
 #ifdef DEBUG_CHARS
        printf("putback '%c'\n", pc);
diff --git a/main.c b/main.c
index 0c95dbd..e10f01e 100644 (file)
--- a/main.c
+++ b/main.c
@@ -495,6 +495,9 @@ int main(int argc, char **argv)
                }
        }
 
+       /* we do the lowering in ast2firm */
+       firm_opt.lower_bitfields = FALSE;
+
        if(help_displayed) {
                return !argument_errors;
        }
index 71f125b..c8521ef 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -3055,13 +3055,7 @@ type_t *revert_automatic_type_conversion(const expression_t *expression)
        }
        case EXPR_SELECT: {
                const select_expression_t *select = &expression->select;
-               type_t *orig_type = select->compound_entry->type;
-               type_t *type      = skip_typeref(orig_type);
-               if(type->kind == TYPE_BITFIELD) {
-                       return type->bitfield.base;
-               } else {
-                       return orig_type;
-               }
+               return select->compound_entry->type;
        }
        case EXPR_UNARY_DEREFERENCE: {
                expression_t   *value        = expression->unary.value;
@@ -3119,10 +3113,6 @@ static expression_t *parse_reference(void)
        }
 
        type_t *type         = declaration->type;
-       type_t *skipped_type = skip_typeref(type);
-       if(skipped_type->kind == TYPE_BITFIELD) {
-               type = skipped_type->bitfield.base;
-       }
 
        /* we always do the auto-type conversions; the & and sizeof parser contains
         * code to revert this! */
@@ -3713,13 +3703,19 @@ static expression_t *parse_select_expression(unsigned precedence,
        /* we always do the auto-type conversions; the & and sizeof parser contains
         * code to revert this! */
        type_t *expression_type = automatic_type_conversion(iter->type);
-       if(expression_type->kind == TYPE_BITFIELD) {
-               expression_type = expression_type->bitfield.base;
-       }
 
        select->select.compound_entry = iter;
        select->base.datatype         = expression_type;
 
+       if(expression_type->kind == TYPE_BITFIELD) {
+               expression_t *extract
+                       = allocate_expression_zero(EXPR_UNARY_BITFIELD_EXTRACT);
+               extract->unary.value   = select;
+               extract->base.datatype = expression_type->bitfield.base;
+
+               return extract;
+       }
+
        return select;
 }
 
@@ -4410,15 +4406,19 @@ static void semantic_binexpr_assign(binary_expression_t *expression)
                return;
        }
        if(type_left->base.qualifiers & TYPE_QUALIFIER_CONST) {
-               errorf(HERE, "assignment to readonly location '%E' (type '%T')", left, orig_type_left);
+               errorf(HERE, "assignment to readonly location '%E' (type '%T')", left,
+                      orig_type_left);
                return;
        }
        if(is_type_incomplete(type_left)) {
-               errorf(HERE, "left-hand side of assignment '%E' has incomplete type '%T'", left, orig_type_left);
+               errorf(HERE,
+                      "left-hand side of assignment '%E' has incomplete type '%T'",
+                      left, orig_type_left);
                return;
        }
        if(is_type_compound(type_left) && has_const_fields(&type_left->compound)) {
-               errorf(HERE, "cannot assign to '%E' because compound type '%T' has readonly fields", left, orig_type_left);
+               errorf(HERE, "cannot assign to '%E' because compound type '%T' has readonly fields",
+                      left, orig_type_left);
                return;
        }