pointer arithmetic.

fix issue with classes not doing nonvirtual properly.
fix virtual functions existing separately from basic fields.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4642 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2014-04-14 09:16:41 +00:00
parent 45545825a4
commit 3d71834373
5 changed files with 133 additions and 45 deletions

View File

@ -379,6 +379,16 @@ enum qcop_e {
OP_BITCLR_F,
OP_BITCLR_I,
OP_ADD_PF,
OP_ADD_FP,
OP_ADD_PI,
OP_ADD_IP,
OP_SUB_PF,
OP_SUB_PI,
OP_SUB_PP,
OP_NUMOPS
};

View File

@ -365,6 +365,7 @@ typedef struct QCC_def_s
pbool isstatic:1;
pbool subscoped_away:1;
pbool followptr:1;
pbool strip:1;
temp_t *temp;
} QCC_def_t;
@ -377,6 +378,7 @@ typedef struct
REF_POINTER,//*(pointerdef+wordindex) - maths...
REF_FIELD, //(entity.field) - reading is a single load, writing requires address+storep
REF_STRING, //"hello"[1]=='e' - special opcodes, or str2chr builtin, or something
REF_NONVIRTUAL //(global.ofs) - identical to global except for function calls, where index can be used to provide the 'newself' for the call.
} type;
QCC_def_t *base;
@ -833,6 +835,7 @@ void QCC_PR_NewLine (pbool incomment);
#define GDF_SAVED 1
#define GDF_STATIC 2
#define GDF_CONST 4
#define GDF_STRIP 8 //always stripped, regardless of optimisations. used for class member fields
QCC_def_t *QCC_PR_GetDef (QCC_type_t *type, char *name, QCC_def_t *scope, pbool allocate, int arraysize, unsigned int flags);
char *QCC_PR_CheckCompConstTooltip(char *word, char *outstart, char *outend);

View File

@ -594,6 +594,14 @@ QCC_opcode_t pr_opcodes[] =
{7, "&~", "BITCLR_F", 6, ASSOC_LEFT, &type_float, &type_float, &type_float},
{7, "&~", "BITCLR_I", 6, ASSOC_LEFT, &type_integer, &type_integer, &type_integer},
{7, "+", "ADD_PF", 6, ASSOC_LEFT, &type_pointer, &type_float, &type_pointer},
{7, "+", "ADD_FP", 6, ASSOC_LEFT, &type_float, &type_pointer, &type_pointer},
{7, "+", "ADD_PI", 6, ASSOC_LEFT, &type_pointer, &type_integer, &type_pointer},
{7, "+", "ADD_IP", 6, ASSOC_LEFT, &type_integer, &type_pointer, &type_pointer},
{7, "-", "SUB_PF", 6, ASSOC_LEFT, &type_pointer, &type_float, &type_pointer},
{7, "-", "SUB_PI", 6, ASSOC_LEFT, &type_pointer, &type_integer, &type_pointer},
{7, "-", "SUB_PP", 6, ASSOC_LEFT, &type_pointer, &type_pointer, &type_integer},
{0, NULL}
};
@ -854,6 +862,10 @@ QCC_opcode_t *opcodeprioritized[TOP_PRIORITY+1][128] =
&pr_opcodes[OP_ADD_FI],
&pr_opcodes[OP_ADD_IF],
&pr_opcodes[OP_ADD_SF],
&pr_opcodes[OP_ADD_PF],
&pr_opcodes[OP_ADD_FP],
&pr_opcodes[OP_ADD_PI],
&pr_opcodes[OP_ADD_IP],
&pr_opcodes[OP_SUB_F],
&pr_opcodes[OP_SUB_V],
@ -861,6 +873,9 @@ QCC_opcode_t *opcodeprioritized[TOP_PRIORITY+1][128] =
&pr_opcodes[OP_SUB_FI],
&pr_opcodes[OP_SUB_IF],
&pr_opcodes[OP_SUB_S],
&pr_opcodes[OP_SUB_PF],
&pr_opcodes[OP_SUB_PI],
&pr_opcodes[OP_SUB_PP],
NULL
}, { //5
@ -2456,6 +2471,42 @@ QCC_def_t *QCC_PR_StatementFlags (QCC_opcode_t *op, QCC_def_t *var_a, QCC_def_t
// QCC_PR_ParseWarning(0, "OP_LOADA_STRUCT: cannot emulate");
break;
case OP_ADD_PF:
case OP_ADD_FP:
case OP_ADD_PI:
case OP_ADD_IP:
numstatements--;
var_c = (op == &pr_opcodes[OP_ADD_PF] || op == &pr_opcodes[OP_ADD_PI])?var_a:var_b;
var_b = (op == &pr_opcodes[OP_ADD_PF] || op == &pr_opcodes[OP_ADD_PI])?var_b:var_a;
QCC_UnFreeTemp(var_c);
if (op == &pr_opcodes[OP_ADD_FP] || op == &pr_opcodes[OP_ADD_PF])
var_b = QCC_SupplyConversion(var_b, ev_integer, true); //FIXME: this should be an unconditional float->int conversion
var_b = QCC_PR_StatementFlags(&pr_opcodes[OP_MUL_I], var_b, QCC_MakeIntConst(var_c->type->size), NULL, 0);
QCC_FreeTemp(var_c);
return QCC_PR_StatementFlags(&pr_opcodes[OP_ADD_PIW], var_c, var_b, NULL, 0);
case OP_SUB_PF:
case OP_SUB_PI:
numstatements--;
var_c = var_a;
var_b = var_b;
QCC_UnFreeTemp(var_c);
if (op == &pr_opcodes[OP_SUB_PF])
var_b = QCC_SupplyConversion(var_b, ev_integer, true); //FIXME: this should be an unconditional float->int conversion
//fixme: word size
var_b = QCC_PR_StatementFlags(&pr_opcodes[OP_MUL_I], var_b, QCC_MakeIntConst(var_c->type->size*4), NULL, 0);
QCC_FreeTemp(var_c);
return QCC_PR_StatementFlags(&pr_opcodes[OP_SUB_I], var_c, var_b, NULL, 0);
case OP_SUB_PP:
numstatements--;
if (typecmp(var_a->type, var_b->type))
QCC_PR_ParseError(0, "incompatible pointer types");
//determine byte offset
var_c = QCC_PR_StatementFlags(&pr_opcodes[OP_SUB_I], var_a, var_b, NULL, 0);
//determine divisor (fixme: word size)
var_b = QCC_MakeIntConst(var_c->type->size*4);
//divide the result
return QCC_PR_StatementFlags(&pr_opcodes[OP_DIV_I], var_c, var_b, NULL, 0);
case OP_ADD_I:
{
QCC_def_t *arg[2] = {var_a, var_b};
@ -3257,7 +3308,7 @@ QCC_ref_t *QCC_PR_GenerateAddressOf(QCC_ref_t *retbuf, QCC_ref_t *operand)
REF_GLOBAL,
QCC_PR_Statement(&pr_opcodes[OP_ADDRESS], operand->base, operand->index, NULL),
NULL,
(operand->index->type->type == ev_field)?operand->index->type->aux_type:type_variant,
QCC_PR_PointerType((operand->index->type->type == ev_field)?operand->index->type->aux_type:type_variant),
true);
}
if (operand->type == REF_GLOBAL || operand->type == REF_ARRAY)
@ -3698,6 +3749,11 @@ QCC_def_t *QCC_PR_ParseFunctionCall (QCC_ref_t *funcref) //warning, the func cou
newself = funcref->base;
func = QCC_RefToDef(funcref, false);
}
else if (funcref->type == REF_NONVIRTUAL)
{
newself = funcref->index;
func = QCC_RefToDef(funcref, false);
}
else
{
newself = NULL;
@ -5085,6 +5141,14 @@ static QCC_ref_t *QCC_PR_ParseField(QCC_ref_t *refbuf, QCC_ref_t *lhs)
}
else
{
if (field->type == REF_GLOBAL && strstr(field->base->name, "::"))
{
QCC_def_t *theent = QCC_RefToDef(lhs, true);
*refbuf = *field;
refbuf->type = REF_NONVIRTUAL;
refbuf->index = theent;
return refbuf;
}
if (t->parentclass)
QCC_PR_ParseError(ERR_INTERNAL, "%s is not a field of class %s", QCC_RefToDef(field, false)->name, t->name);
else
@ -5479,10 +5543,19 @@ QCC_ref_t *QCC_PR_ParseRefValue (QCC_ref_t *refbuf, QCC_type_t *assumeclass, pbo
{ //try getting a member.
QCC_type_t *type;
type = assumeclass;
while(!d && type)
while(type)
{
//look for virtual things
sprintf(membername, "%s::"MEMBERFIELDNAME, type->name, name);
d = QCC_PR_GetDef (NULL, membername, pr_scope, false, 0, false);
if (d)
break;
//look for non-virtual things (functions: after virtual stuff, because this will find the actual function def too)
sprintf(membername, "%s::%s", type->name, name);
d = QCC_PR_GetDef (NULL, membername, pr_scope, false, 0, false);
if (d)
break;
type = type->parentclass;
}
@ -6340,11 +6413,14 @@ QCC_def_t *QCC_RefToDef(QCC_ref_t *ref, pbool freetemps)
ref->base = origv;
ref->index = NULL;
ref->readonly = true;
return origv;
}
switch(ref->type)
{
case REF_NONVIRTUAL:
break;
case REF_GLOBAL:
case REF_ARRAY:
if (ref->index)
@ -6456,7 +6532,7 @@ QCC_def_t *QCC_StoreToRef(QCC_ref_t *dest, QCC_def_t *source, pbool readable, pb
{
QCC_def_t *dd;
// QCC_PR_ParseWarning(0, "FIXME: trying to do references: assignments to arrays with const offset not supported.\n");
case REF_NONVIRTUAL:
dest->base->references++;
dd = (void *)qccHunkAlloc (sizeof(QCC_def_t));
memset (dd, 0, sizeof(QCC_def_t));
@ -6650,6 +6726,7 @@ QCC_opcode_t *QCC_PR_ChooseOpcode(QCC_def_t *lhs, QCC_def_t *rhs, QCC_opcode_t *
if (op->associative!=ASSOC_LEFT)
{//assignment
#if 0
if (op->type_a == &type_pointer) //ent var
{
/*FIXME: I don't like this code*/
@ -6663,6 +6740,7 @@ QCC_opcode_t *QCC_PR_ChooseOpcode(QCC_def_t *lhs, QCC_def_t *rhs, QCC_opcode_t *
c = QCC_canConv(rhs, (*op->type_c)->type);
}
else
#endif
{
c=QCC_canConv(rhs, (*op->type_b)->type);
if (type_a != (*op->type_a)->type) //in this case, a is the final assigned value
@ -9821,6 +9899,7 @@ QCC_def_t *QCC_PR_DummyDef(QCC_type_t *type, char *name, QCC_def_t *scope, int a
def->saved = !!(flags & GDF_SAVED);
def->constant = !!(flags & GDF_CONST);
def->isstatic = !!(flags & GDF_STATIC);
def->strip = !!(flags & GDF_STRIP);
def->ofs = ofs + type->size*a;
if (!first)

View File

@ -4379,13 +4379,13 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
QCC_PR_Expect(";");
//static members are technically funny-named globals, and do not generate fields.
if (isstatic || (newparm->type == ev_function && !arraysize))
//static members are technically just funny-named globals, and do not generate fields.
if (isnonvirt || isstatic || (newparm->type == ev_function && !arraysize))
{
sprintf(membername, "%s::%s", classname, parmname);
QCC_PR_GetDef(newparm, membername, NULL, true, 0, GDF_CONST);
if (isstatic)
if (isnonvirt || isstatic)
continue;
}
@ -4471,7 +4471,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
//actually, that seems pointless.
sprintf(membername, "%s::"MEMBERFIELDNAME, classname, parmname);
// printf("define %s -> %s\n", membername, d->name);
d = QCC_PR_DummyDef(fieldtype, membername, pr_scope, 0, d->ofs, true, GDF_CONST);
d = QCC_PR_DummyDef(fieldtype, membername, pr_scope, 0, d->ofs, true, GDF_CONST|GDF_STRIP);
d->references++; //always referenced, so you can inherit safely.
}

View File

@ -875,6 +875,9 @@ pbool QCC_WriteData (int crc)
}
}
if (def->strip)
continue;
if (def->type->type == ev_function)
{
if (opt_function_names && def->initialized && functions[G_FUNCTION(def->ofs)].first_statement<0)
@ -1482,49 +1485,42 @@ strofs = (strofs+3)&~3;
printf("Compile finished: %s\n", destfile);
if (!debugtarget)
if (statement_linenums)
{
if (opt_filenames)
unsigned int lnotype = *(unsigned int*)"LNOF";
unsigned int version = 1;
pbool gz = false;
while(1)
{
printf("Not writing linenumbers file due to conflicting optimisation (try -Ono-f)\n");
}
else
{
unsigned int lnotype = *(unsigned int*)"LNOF";
unsigned int version = 1;
pbool gz = false;
while(1)
{
char *ext;
ext = strrchr(destfile, '.');
if (strchr(ext, '/') || strchr(ext, '\\'))
break;
if (!stricmp(ext, ".gz"))
{
*ext = 0;
gz = true;
continue;
}
*ext = 0;
char *ext;
ext = strrchr(destfile, '.');
if (strchr(ext, '/') || strchr(ext, '\\'))
break;
}
if (strlen(destfile) < sizeof(destfile)-(4+3))
if (!stricmp(ext, ".gz"))
{
strcat(destfile, ".lno");
if (gz)
strcat(destfile, ".gz");
if (verbose)
printf("Writing %s for debugging\n", destfile);
h = SafeOpenWrite (destfile, 2*1024*1024);
SafeWrite (h, &lnotype, sizeof(int));
SafeWrite (h, &version, sizeof(int));
SafeWrite (h, &numglobaldefs, sizeof(int));
SafeWrite (h, &numpr_globals, sizeof(int));
SafeWrite (h, &numfielddefs, sizeof(int));
SafeWrite (h, &numstatements, sizeof(int));
SafeWrite (h, statement_linenums, numstatements*sizeof(int));
SafeClose (h);
*ext = 0;
gz = true;
continue;
}
*ext = 0;
break;
}
if (strlen(destfile) < sizeof(destfile)-(4+3))
{
strcat(destfile, ".lno");
if (gz)
strcat(destfile, ".gz");
if (verbose)
printf("Writing %s for debugging\n", destfile);
h = SafeOpenWrite (destfile, 2*1024*1024);
SafeWrite (h, &lnotype, sizeof(int));
SafeWrite (h, &version, sizeof(int));
SafeWrite (h, &numglobaldefs, sizeof(int));
SafeWrite (h, &numpr_globals, sizeof(int));
SafeWrite (h, &numfielddefs, sizeof(int));
SafeWrite (h, &numstatements, sizeof(int));
SafeWrite (h, statement_linenums, numstatements*sizeof(int));
SafeClose (h);
}
}