]> git.xonotic.org Git - xonotic/gmqcc.git/commitdiff
Merging master to handle vector members, fields, and members of vector fields
authorWolfgang (Blub) Bumiller <blub@speed.at>
Sun, 12 Aug 2012 08:08:41 +0000 (10:08 +0200)
committerWolfgang (Blub) Bumiller <blub@speed.at>
Sun, 12 Aug 2012 08:08:41 +0000 (10:08 +0200)
1  2 
ast.c
gmqcc.h
ir.c
ir.h

diff --combined ast.c
index 5f947b0e02903709cde800090c03f877a1b31048,e6d28a61d19a4dcc32672c794a52f62657a4e49c..117f845ae0bc816b40a99f5a3ab0a9741ace5ac6
--- 1/ast.c
--- 2/ast.c
+++ b/ast.c
@@@ -94,6 -94,15 +94,15 @@@ static ast_value* ast_value_copy(const 
      return cp;
  }
  
+ static ast_expression* ast_shallow_type(lex_ctx ctx, int vtype)
+ {
+     ast_instantiate(ast_expression, ctx, ast_expression_delete_full);
+     self->expression.codegen = NULL;
+     self->expression.next    = NULL;
+     self->expression.vtype   = vtype;
+     return self;
+ }
  static ast_expression* ast_type_copy(lex_ctx ctx, const ast_expression *ex)
  {
      size_t i;
@@@ -202,18 -211,6 +211,18 @@@ ast_binary* ast_binary_new(lex_ctx ctx
      self->left = left;
      self->right = right;
  
 +    if (op >= INSTR_EQ_F && op <= INSTR_GT)
 +        self->expression.vtype = TYPE_FLOAT;
 +    else if (op == INSTR_AND || op == INSTR_OR ||
 +             op == INSTR_BITAND || op == INSTR_BITOR)
 +        self->expression.vtype = TYPE_FLOAT;
 +    else if (op == INSTR_MUL_VF || op == INSTR_MUL_FV)
 +        self->expression.vtype = TYPE_VECTOR;
 +    else if (op == INSTR_MUL_V)
 +        self->expression.vtype = TYPE_FLOAT;
 +    else
 +        self->expression.vtype = left->expression.vtype;
 +
      return self;
  }
  
@@@ -306,10 -303,22 +315,22 @@@ ast_member* ast_member_new(lex_ctx ctx
          return NULL;
      }
  
+     if (owner->expression.vtype != TYPE_FLOAT &&
+         owner->expression.vtype != TYPE_FIELD) {
+         printf("ast_member on an invalid owner of type %i\n", (int)owner->expression.vtype);
+         mem_d(self);
+         return NULL;
+     }
      ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_member_codegen);
  
-     self->expression.vtype = TYPE_FLOAT;
-     self->expression.next  = NULL;
+     if (owner->expression.vtype == TYPE_VECTOR) {
+         self->expression.vtype = TYPE_FLOAT;
+         self->expression.next  = NULL;
+     } else {
+         self->expression.vtype = TYPE_FIELD;
+         self->expression.next = ast_shallow_type(ctx, TYPE_FLOAT);
+     }
  
      self->owner = owner;
      self->field = field;
@@@ -628,11 -637,21 +649,23 @@@ bool ast_global_codegen(ast_value *self
          return true;
      }
  
+     if (self->expression.vtype == TYPE_FIELD) {
+         v = ir_builder_create_field(ir, self->name, self->expression.next->expression.vtype);
+         if (!v)
+             return false;
+         if (self->isconst) {
+             printf("TODO: constant field pointers with value\n");
+             goto error;
+         }
+         self->ir_v = v;
+         return true;
+     }
      v = ir_builder_create_global(ir, self->name, self->expression.vtype);
 -    if (!v)
 +    if (!v) {
 +        printf("ir_builder_create_global failed\n");
          return false;
 +    }
  
      if (self->isconst) {
          switch (self->expression.vtype)
@@@ -954,14 -973,17 +987,17 @@@ bool ast_entfield_codegen(ast_entfield 
  bool ast_member_codegen(ast_member *self, ast_function *func, bool lvalue, ir_value **out)
  {
      ast_expression_codegen *cgen;
-     ir_value *vec, *field;
+     ir_value *vec;
  
      cgen = self->owner->expression.codegen;
      if (!(*cgen)((ast_expression*)(self->owner), func, true, &vec))
          return false;
  
-     if (vec->vtype != TYPE_VECTOR)
+     if (vec->vtype != TYPE_VECTOR &&
+         !(vec->vtype == TYPE_FIELD && self->owner->expression.next->expression.vtype == TYPE_VECTOR))
+     {
          return false;
+     }
  
      *out = ir_value_vector_member(vec, self->field);
  
diff --combined gmqcc.h
index 4e1c641c2579f8e66842e38dc71e44ad4878de87,26428b82ac6c104063a0d80b5ae830f9ebbcc0fa..b27998b1262ce1426c0f2cdb0ab8a1e3943998e8
+++ b/gmqcc.h
@@@ -179,6 -179,95 +179,6 @@@ typedef char int64_size_is_correct  [si
  typedef char uintptr_size_is_correct[sizeof(intptr_t) == sizeof(int*)?1:-1];
  typedef char intptr_size_is_correct [sizeof(uintptr_t)== sizeof(int*)?1:-1];
  
 -/*===================================================================*/
 -/*============================ lex.c ================================*/
 -/*===================================================================*/
 -typedef struct lex_file_t {
 -    FILE *file;        /* file handler */
 -    char *name;        /* name of file */
 -    char  peek  [5];
 -    char  lastok[8192];
 -
 -    int   last;    /* last token                   */
 -    int   current; /* current token                */
 -    int   length;  /* bytes left to parse          */
 -    int   size;    /* never changes (size of file) */
 -    int   line;    /* what line are we on?         */
 -} lex_file;
 -
 -/*
 - * It's important that this table never exceed 32 keywords, the ascii
 - * table starts at 33 (and we don't want conflicts)
 - */
 -enum {
 -    TOKEN_DO       ,
 -    TOKEN_ELSE     ,
 -    TOKEN_IF       ,
 -    TOKEN_WHILE    ,
 -    TOKEN_BREAK    ,
 -    TOKEN_CONTINUE ,
 -    TOKEN_RETURN   ,
 -    TOKEN_GOTO     ,
 -    TOKEN_FOR      ,   /* extension */
 -    TOKEN_TYPEDEF  ,   /* extension */
 -
 -    /* ensure the token types are out of the  */
 -    /* bounds of anyothers that may conflict. */
 -    TOKEN_FLOAT    = 110,
 -    TOKEN_VECTOR        ,
 -    TOKEN_STRING        ,
 -    TOKEN_ENTITY        ,
 -    TOKEN_VOID
 -};
 -
 -/*
 - * Lexer state constants, these are numbers for where exactly in
 - * the lexing the lexer is at. Or where it decided to stop if a lexer
 - * error occurs.  These numbers must be > where the ascii-table ends
 - * and > the last type token which is TOKEN_VOID
 - */
 -enum {
 -    LEX_COMMENT = 1128,
 -    LEX_CHRLIT        ,
 -    LEX_STRLIT        ,
 -    LEX_IDENT
 -};
 -
 -int       lex_token  (lex_file *);
 -void      lex_reset  (lex_file *);
 -void      lex_close  (lex_file *);
 -void      lex_parse  (lex_file *);
 -lex_file *lex_include(lex_file *, const char *);
 -void      lex_init   (const char *, lex_file **);
 -
 -/*===================================================================*/
 -/*========================== error.c ================================*/
 -/*===================================================================*/
 -#define ERROR_LEX      (SHRT_MAX+0)
 -#define ERROR_PARSE    (SHRT_MAX+1)
 -#define ERROR_INTERNAL (SHRT_MAX+2)
 -#define ERROR_COMPILER (SHRT_MAX+3)
 -#define ERROR_PREPRO   (SHRT_MAX+4)
 -int error(lex_file *, int, const char *, ...);
 -
 -/*===================================================================*/
 -/*========================== parse.c ================================*/
 -/*===================================================================*/
 -int parse_gen(lex_file *);
 -
 -/*===================================================================*/
 -/*========================== typedef.c ==============================*/
 -/*===================================================================*/
 -typedef struct typedef_node_t {
 -    char      *name;
 -} typedef_node;
 -
 -void          typedef_init();
 -void          typedef_clear();
 -typedef_node *typedef_find(const char *);
 -int           typedef_add (lex_file *file, const char *, const char *);
 -
 -
  /*===================================================================*/
  /*=========================== util.c ================================*/
  /*===================================================================*/
@@@ -278,16 -367,12 +278,16 @@@ enum 
      TYPE_FIELD    ,
      TYPE_FUNCTION ,
      TYPE_POINTER  ,
 -    /* TYPE_INTEGER  , */
 +    TYPE_INTEGER  ,
 +    TYPE_QUATERNION  ,
 +    TYPE_MATRIX  ,
      TYPE_VARIANT  ,
  
      TYPE_COUNT
  };
  
 +extern const char *type_name[TYPE_COUNT];
 +
  extern size_t type_sizeof[TYPE_COUNT];
  extern uint16_t type_store_instr[TYPE_COUNT];
  /* could use type_store_instr + INSTR_STOREP_F - INSTR_STORE_F
@@@ -400,8 -485,8 +400,8 @@@ enum 
      INSTR_DONE,
      INSTR_MUL_F,
      INSTR_MUL_V,
 -    INSTR_MUL_FV,
      INSTR_MUL_VF,
 +    INSTR_MUL_FV,
      INSTR_DIV_F,
      INSTR_ADD_F,
      INSTR_ADD_V,
      INSTR_BITAND,
      INSTR_BITOR,
  
 +/* warning: will be reordered */
 +    INSTR_MUL_Q,
 +    INSTR_MUL_QF,
 +    INSTR_MUL_M,
 +    INSTR_MUL_MF,
 +    INSTR_EQ_Q,
 +    INSTR_EQ_M,
 +    INSTR_NE_Q,
 +    INSTR_NE_M,
 +    INSTR_LOAD_Q,
 +    INSTR_LOAD_M,
 +    INSTR_STORE_Q,
 +    INSTR_STORE_M,
 +    INSTR_STOREP_Q,
 +    INSTR_STOREP_M,
 +    INSTR_INV_Q,
 +    INSTR_INV_M,
      /*
       * Virtual instructions used by the assembler
       * keep at the end but before virtual instructions
@@@ -540,8 -608,8 +540,8 @@@ static const struct 
      { "DONE"      , 1, 4 },
      { "MUL_F"     , 3, 5 },
      { "MUL_V"     , 3, 5 },
 -    { "MUL_FV"    , 3, 6 },
      { "MUL_VF"    , 3, 6 },
 +    { "MUL_FV"    , 3, 6 },
      { "DIV"       , 0, 3 },
      { "ADD_F"     , 3, 5 },
      { "ADD_V"     , 3, 5 },
      { "OR"        , 0, 2 },
      { "BITAND"    , 0, 6 },
      { "BITOR"     , 0, 5 },
 +
 +    { "MUL_Q"     , 3, 5 },
 +    { "MUL_QF"    , 3, 6 },
 +    { "MUL_M"     , 3, 5 },
 +    { "MUL_MF"    , 3, 6 },
 +    { "EQ_Q"      , 0, 4 },
 +    { "EQ_M"      , 0, 4 },
 +    { "NE_Q"      , 0, 4 },
 +    { "NE_M"      , 0, 4 },
 +    { "FIELD_Q"   , 0, 7 },
 +    { "FIELD_M"   , 0, 7 },
 +    { "STORE_Q"   , 0, 7 },
 +    { "STORE_M"   , 0, 7 },
 +    { "STOREP_Q"  , 0, 8 },
 +    { "STOREP_M"  , 0, 8 },
 +    { "INV_Q"     , 0, 5 },
 +    { "INV_M"     , 0, 5 },
 +
      { "END"       , 0, 3 } /* virtual assembler instruction */
  };
  
@@@ -781,16 -831,6 +781,16 @@@ void Tself##_##mem##_clear(Tself *self
      (owner)->mem##_alloc = 0;       \
  }
  
 +#define MEM_VECTOR_MOVE(from, mem, to, tm)   \
 +{                                            \
 +    (to)->tm = (from)->mem;                  \
 +    (to)->tm##_count = (from)->mem##_count;  \
 +    (to)->tm##_alloc = (from)->mem##_alloc;  \
 +    (from)->mem = NULL;                      \
 +    (from)->mem##_count = 0;                 \
 +    (from)->mem##_alloc = 0;                 \
 +}
 +
  #define MEM_VEC_FUNCTIONS(Tself, Twhat, mem) \
  MEM_VEC_FUN_REMOVE(Tself, Twhat, mem)        \
  MEM_VEC_FUN_ADD(Tself, Twhat, mem)
@@@ -812,14 -852,6 +812,14 @@@ typedef struct 
      float x, y, z;
  } vector;
  
 +typedef float matrix[4][4]; /* OpenGL layout */
 +typedef float quaternion[4]; /* order: x, y, z, w */
 +#define MATRIX(axis, elem) ((4*(axis)) + (elem))
 +#define QUAT_X 0
 +#define QUAT_Y 1
 +#define QUAT_Z 2
 +#define QUAT_W 3
 +
  /*
   * A shallow copy of a lex_file to remember where which ast node
   * came from.
@@@ -885,6 -917,7 +885,7 @@@ typedef struct qc_program_s 
      MEM_VECTOR_MAKE(char,                   strings);
      MEM_VECTOR_MAKE(qcint,                  globals);
      MEM_VECTOR_MAKE(qcint,                  entitydata);
+     MEM_VECTOR_MAKE(bool,                   entitypool);
  
      size_t tempstring_start;
      size_t tempstring_at;
diff --combined ir.c
index f34cc911a3242b7100e7f1153203367ae1003392,e01da4d4e102c8c6e9d93e5be5f97ed3d047b876..78c97c7058e6230e397c4ec8a9da343555a0589c
--- 1/ir.c
--- 2/ir.c
+++ b/ir.c
   * Type sizes used at multiple points in the IR codegen
   */
  
 +const char *type_name[TYPE_COUNT] = {
 +    "void",
 +    "string",
 +    "float",
 +    "vector",
 +    "entity",
 +    "field",
 +    "function",
 +    "pointer",
 +#if 0
 +    "integer",
 +#endif
 +    "quaternion",
 +    "matrix",
 +    "variant"
 +};
 +
  size_t type_sizeof[TYPE_COUNT] = {
      1, /* TYPE_VOID     */
      1, /* TYPE_STRING   */
@@@ -58,9 -41,7 +58,9 @@@
  #if 0
      1, /* TYPE_INTEGER  */
  #endif
 -    3, /* TYPE_VARIANT  */
 +    4, /* TYPE_QUATERNION */
 +    16, /* TYPE_MATRIX */
 +    16, /* TYPE_VARIANT  */
  };
  
  uint16_t type_store_instr[TYPE_COUNT] = {
      INSTR_STORE_FNC,
      INSTR_STORE_ENT, /* should use I */
  #if 0
 -    INSTR_STORE_ENT, /* integer type */
 +    INSTR_STORE_I, /* integer type */
  #endif
 -    INSTR_STORE_V, /* variant, should never be accessed */
 +    INSTR_STORE_Q,
 +    INSTR_STORE_M,
 +
 +    INSTR_STORE_M, /* variant, should never be accessed */
  };
  
  uint16_t type_storep_instr[TYPE_COUNT] = {
  #if 0
      INSTR_STOREP_ENT, /* integer type */
  #endif
 -    INSTR_STOREP_V, /* variant, should never be accessed */
 +    INSTR_STOREP_Q,
 +    INSTR_STOREP_M,
 +
 +    INSTR_STOREP_M, /* variant, should never be accessed */
  };
  
  MEM_VEC_FUNCTIONS(ir_value_vector, ir_value*, v)
@@@ -212,14 -187,9 +212,14 @@@ ir_value* ir_builder_get_global(ir_buil
  
  ir_value* ir_builder_create_global(ir_builder *self, const char *name, int vtype)
  {
 -    ir_value *ve = ir_builder_get_global(self, name);
 -    if (ve) {
 -        return NULL;
 +    ir_value *ve;
 +
 +    if (name && name[0] != '#')
 +    {
 +        ve = ir_builder_get_global(self, name);
 +        if (ve) {
 +            return NULL;
 +        }
      }
  
      ve = ir_value_var(name, store_global, vtype);
@@@ -559,6 -529,8 +559,8 @@@ void ir_value_code_setaddr(ir_value *se
  
  int32_t ir_value_code_addr(const ir_value *self)
  {
+     if (self->store == store_return)
+         return OFS_RETURN + self->code.addroffset;
      return self->code.globaladdr + self->code.addroffset;
  }
  
@@@ -594,13 -566,29 +596,29 @@@ ir_value* ir_value_vector_member(ir_val
      if (self->members[member])
          return self->members[member];
  
-     m = ir_value_var(self->name, self->store, TYPE_FLOAT);
-     if (!m)
-         return NULL;
-     m->context = self->context;
+     if (self->vtype == TYPE_VECTOR)
+     {
+         m = ir_value_var(self->name, self->store, TYPE_FLOAT);
+         if (!m)
+             return NULL;
+         m->context = self->context;
  
-     self->members[member] = m;
-     m->code.addroffset = member;
+         self->members[member] = m;
+         m->code.addroffset = member;
+     }
+     else if (self->vtype == TYPE_FIELD)
+     {
+         if (self->fieldtype != TYPE_VECTOR)
+             return NULL;
+         m = ir_value_var(self->name, self->store, TYPE_FIELD);
+         if (!m)
+             return NULL;
+         m->fieldtype = TYPE_FLOAT;
+         m->context = self->context;
+         self->members[member] = m;
+         m->code.addroffset = member;
+     }
  
      return m;
  }
@@@ -676,24 -664,15 +694,33 @@@ bool ir_value_set_vector(ir_value *self
      return true;
  }
  
 +bool ir_value_set_quaternion(ir_value *self, quaternion v)
 +{
 +    if (self->vtype != TYPE_QUATERNION)
 +        return false;
 +    memcpy(&self->constval.vquat, v, sizeof(self->constval.vquat));
 +    self->isconst = true;
 +    return true;
 +}
 +
 +bool ir_value_set_matrix(ir_value *self, matrix v)
 +{
 +    if (self->vtype != TYPE_MATRIX)
 +        return false;
 +    memcpy(&self->constval.vmat, v, sizeof(self->constval.vmat));
 +    self->isconst = true;
 +    return true;
 +}
 +
+ bool ir_value_set_field(ir_value *self, ir_value *fld)
+ {
+     if (self->vtype != TYPE_FIELD)
+         return false;
+     self->constval.vpointer = fld;
+     self->isconst = true;
+     return true;
+ }
  bool ir_value_set_string(ir_value *self, const char *str)
  {
      if (self->vtype != TYPE_STRING)
@@@ -945,22 -924,26 +972,26 @@@ bool ir_values_overlap(const ir_value *
  
  bool ir_block_create_store_op(ir_block *self, int op, ir_value *target, ir_value *what)
  {
-     if (target->store == store_value) {
+     ir_instr *in = ir_instr_new(self, op);
+     if (!in)
+         return false;
+     if (target->store == store_value &&
+         (op < INSTR_STOREP_F || op > INSTR_STOREP_FNC))
+     {
          fprintf(stderr, "cannot store to an SSA value\n");
          fprintf(stderr, "trying to store: %s <- %s\n", target->name, what->name);
+         fprintf(stderr, "instruction: %s\n", asm_instr[op].m);
+         return false;
+     }
+     if (!ir_instr_op(in, 0, target, true) ||
+         !ir_instr_op(in, 1, what, false)  ||
+         !ir_block_instr_add(self, in) )
+     {
          return false;
-     } else {
-         ir_instr *in = ir_instr_new(self, op);
-         if (!in)
-             return false;
-         if (!ir_instr_op(in, 0, target, true) ||
-             !ir_instr_op(in, 1, what, false)  ||
-             !ir_block_instr_add(self, in) )
-         {
-             return false;
-         }
-         return true;
      }
+     return true;
  }
  
  bool ir_block_create_store(ir_block *self, ir_value *target, ir_value *what)
  #endif
          op = type_store_instr[vtype];
  
+     if (OPTS_FLAG(ADJUST_VECTOR_FIELDS)) {
+         if (op == INSTR_STORE_FLD && what->fieldtype == TYPE_VECTOR)
+             op = INSTR_STORE_V;
+     }
      return ir_block_create_store_op(self, op, target, what);
  }
  
@@@ -997,6 -985,11 +1033,11 @@@ bool ir_block_create_storep(ir_block *s
      vtype = what->vtype;
  
      op = type_storep_instr[vtype];
+     if (OPTS_FLAG(ADJUST_VECTOR_FIELDS)) {
+         if (op == INSTR_STOREP_FLD && what->fieldtype == TYPE_VECTOR)
+             op = INSTR_STOREP_V;
+     }
      return ir_block_create_store_op(self, op, target, what);
  }
  
@@@ -1391,8 -1384,6 +1432,8 @@@ ir_value* ir_block_create_load_from_ent
          case TYPE_POINTER: op = INSTR_LOAD_I;   break;
          case TYPE_INTEGER: op = INSTR_LOAD_I;   break;
  #endif
 +        case TYPE_QUATERNION: op = INSTR_LOAD_Q; break;
 +        case TYPE_MATRIX:     op = INSTR_LOAD_M; break;
          default:
              return NULL;
      }
@@@ -1496,22 -1487,12 +1537,22 @@@ ir_value* ir_block_create_mul(ir_block 
              case TYPE_VECTOR:
                  op = INSTR_MUL_V;
                  break;
 +            case TYPE_QUATERNION:
 +                op = INSTR_MUL_Q;
 +                break;
 +            case TYPE_MATRIX:
 +                op = INSTR_MUL_M;
 +                break;
          }
      } else {
          if ( (l == TYPE_VECTOR && r == TYPE_FLOAT) )
              op = INSTR_MUL_VF;
          else if ( (l == TYPE_FLOAT && r == TYPE_VECTOR) )
              op = INSTR_MUL_FV;
 +        else if ( (l == TYPE_QUATERNION && r == TYPE_FLOAT) )
 +            op = INSTR_MUL_QF;
 +        else if ( (l == TYPE_MATRIX && r == TYPE_FLOAT) )
 +            op = INSTR_MUL_MF;
  #if 0
          else if ( (l == TYPE_VECTOR && r == TYPE_INTEGER) )
              op = INSTR_MUL_VI;
@@@ -2178,10 -2159,18 +2219,18 @@@ static bool gen_global_field(ir_value *
  
          /* copy the field's value */
          ir_value_code_setaddr(global, code_globals_add(code_globals_data[fld->code.globaladdr]));
+         if (global->fieldtype == TYPE_VECTOR) {
+             code_globals_add(code_globals_data[fld->code.globaladdr]+1);
+             code_globals_add(code_globals_data[fld->code.globaladdr]+2);
+         }
      }
      else
      {
          ir_value_code_setaddr(global, code_globals_add(0));
+         if (global->fieldtype == TYPE_VECTOR) {
+             code_globals_add(0);
+             code_globals_add(0);
+         }
      }
      if (global->code.globaladdr < 0)
          return false;
@@@ -2408,8 -2397,10 +2457,10 @@@ tailcall
              stmt.o1.u1 = stmt.o3.u1;
              stmt.o3.u1 = 0;
          }
-         else if (stmt.opcode >= INSTR_STORE_F &&
-                  stmt.opcode <= INSTR_STORE_FNC)
+         else if ((stmt.opcode >= INSTR_STORE_F &&
+                   stmt.opcode <= INSTR_STORE_FNC) ||
+                  (stmt.opcode >= INSTR_STOREP_F &&
+                   stmt.opcode <= INSTR_STOREP_FNC))
          {
              /* 2-operand instructions with A -> B */
              stmt.o2.u1 = stmt.o3.u1;
@@@ -2567,8 -2558,6 +2618,8 @@@ static bool ir_builder_gen_global(ir_bu
          return global->code.globaladdr >= 0;
      }
      case TYPE_VECTOR:
 +    case TYPE_QUATERNION:
 +    case TYPE_MATRIX:
      {
          size_t d;
          if (code_defs_add(def) < 0)
@@@ -2622,13 -2611,42 +2673,42 @@@ static bool ir_builder_gen_field(ir_bui
  
      def.type   = field->vtype;
      def.offset = code_globals_elements;
-     def.name   = field->code.name = code_genstring(field->name);
+     /* create a global named the same as the field */
+     if (opts_standard == COMPILER_GMQCC) {
+         /* in our standard, the global gets a dot prefix */
+         size_t len = strlen(field->name);
+         char name[1024];
+         /* we really don't want to have to allocate this, and 1024
+          * bytes is more than enough for a variable/field name
+          */
+         if (len+2 >= sizeof(name)) {
+             printf("invalid field name size: %u\n", (unsigned int)len);
+             return false;
+         }
+         name[0] = '.';
+         strcpy(name+1, field->name); /* no strncpy - we used strlen above */
+         name[len+1] = 0;
+         def.name = code_genstring(name);
+         fld.name = def.name + 1; /* we reuse that string table entry */
+     } else {
+         /* in plain QC, there cannot be a global with the same name,
+          * and so we also name the global the same.
+          * FIXME: fteqcc should create a global as well
+          * check if it actually uses the same name. Probably does
+          */
+         def.name = code_genstring(field->name);
+         fld.name = def.name;
+     }
+     field->code.name = def.name;
  
      if (code_defs_add(def) < 0)
          return false;
  
-     fld.name = def.name;
-     fld.offset = code_fields_elements;
      fld.type = field->fieldtype;
  
      if (fld.type == TYPE_VOID) {
          return false;
      }
  
+     fld.offset = code_alloc_field(type_sizeof[field->fieldtype]);
      if (code_fields_add(fld) < 0)
          return false;
  
-     if (!code_globals_add(code_alloc_field(type_sizeof[field->fieldtype])))
+     ir_value_code_setaddr(field, code_globals_elements);
+     if (!code_globals_add(fld.offset))
          return false;
+     if (fld.type == TYPE_VECTOR) {
+         if (!code_globals_add(fld.offset+1))
+             return false;
+         if (!code_globals_add(fld.offset+2))
+             return false;
+     }
  
-     ir_value_code_setaddr(field, code_globals_add(fld.offset));
      return field->code.globaladdr >= 0;
  }
  
@@@ -2821,7 -2847,6 +2909,7 @@@ void ir_value_dump(ir_value* v, int (*o
  {
        if (v->isconst) {
                switch (v->vtype) {
 +                  default:
                        case TYPE_VOID:
                                oprintf("(void)");
                                break;
diff --combined ir.h
index a4dddcb937ea5a151f993e599f98b9a0f5b5881b,dccc970f3a632b0dc3fc1167574905b8e78a3ee7..66336d6ae5a6b64a5a8e9a2ff64c2e54c48d22ed
--- 1/ir.h
--- 2/ir.h
+++ b/ir.h
@@@ -55,8 -55,6 +55,8 @@@ typedef struct ir_value_s 
          char    *vstring;
          struct ir_value_s *vpointer;
          struct ir_function_s *vfunc;
 +        quaternion vquat;
 +        matrix     vmat;
      } constval;
  
      struct {
@@@ -97,10 -95,9 +97,11 @@@ bool GMQCC_WARN ir_value_set_int(ir_val
  #endif
  bool GMQCC_WARN ir_value_set_string(ir_value*, const char *s);
  bool GMQCC_WARN ir_value_set_vector(ir_value*, vector v);
+ bool GMQCC_WARN ir_value_set_field(ir_value*, ir_value *fld);
  /*bool   ir_value_set_pointer_v(ir_value*, ir_value* p); */
  /*bool   ir_value_set_pointer_i(ir_value*, int i);       */
 +bool GMQCC_WARN ir_value_set_quaternion(ir_value*, quaternion v);
 +bool GMQCC_WARN ir_value_set_matrix(ir_value*, matrix v);
  
  MEM_VECTOR_PROTO(ir_value, ir_life_entry_t, life);
  /* merge an instruction into the life-range */