* src/SDCC.lex: sdcc now understands both formats:
[fw/sdcc] / src / SDCCsymt.c
index 1e21ade18bd7d4e3b97ace4db3df750c9c069263..35360f205052fbecca4a9b47538cd5220e1a60bc 100644 (file)
@@ -25,6 +25,7 @@
 #include "newalloc.h"
 
 value *aggregateToPointer (value *val);
+void printTypeChainRaw (sym_link * start, FILE * of);
 
 void printFromToType(sym_link *from, sym_link *to) {
   fprintf (stderr, "from type '");
@@ -48,6 +49,7 @@ char *nounName(sym_link *sl) {
     case V_VOID: return "void";
     case V_STRUCT: return "struct";
     case V_LABEL: return "label";
+    case V_BITFIELD: return "bitfield";
     case V_BIT: return "bit";
     case V_SBIT: return "sbit";
     case V_DOUBLE: return "double";
@@ -321,6 +323,37 @@ newStruct (char *tag)
   strncpyz (s->tag, tag, sizeof(s->tag));              /* copy the tag */
   return s;
 }
+  
+/*------------------------------------------------------------------*/
+/* sclsFromPtr - Return the storage class a pointer points into.    */
+/*               S_FIXED is returned for generic pointers or other  */
+/*               unexpected cases                                   */
+/*------------------------------------------------------------------*/
+STORAGE_CLASS
+sclsFromPtr(sym_link *ptr)
+{
+  switch (DCL_TYPE (ptr))
+    {
+    case POINTER:
+      return S_DATA;
+    case GPOINTER:
+      return S_FIXED;
+    case FPOINTER:
+      return S_XDATA;
+    case CPOINTER:
+      return S_CODE;
+    case IPOINTER:
+      return S_IDATA;
+    case PPOINTER:
+      return S_PDATA;
+    case EEPPOINTER:
+      return S_EEPROM;
+    case FUNCTION:
+      return S_CODE;
+    default:
+      return S_FIXED;
+    }
+}
 
 /*------------------------------------------------------------------*/
 /* pointerTypes - do the computation for the pointer types          */
@@ -348,8 +381,6 @@ pointerTypes (sym_link * ptr, sym_link * type)
      storage class of the type */
   if (IS_SPEC (type))
     {
-      DCL_PTR_CONST (ptr) = SPEC_CONST (type);
-      DCL_PTR_VOLATILE (ptr) = SPEC_VOLATILE (type);
       switch (SPEC_SCLS (type))
        {
        case S_XDATA:
@@ -365,7 +396,6 @@ pointerTypes (sym_link * ptr, sym_link * type)
          DCL_TYPE (ptr) = POINTER;
          break;
        case S_CODE:
-         DCL_PTR_CONST (ptr) = port->mem.code_ro;
          DCL_TYPE (ptr) = CPOINTER;
          break;
        case S_EEPROM:
@@ -376,9 +406,7 @@ pointerTypes (sym_link * ptr, sym_link * type)
          break;
        }
       /* the storage class of type ends here */
-      SPEC_SCLS (type) = 
-       SPEC_CONST (type) =
-       SPEC_VOLATILE (type) = 0;
+      SPEC_SCLS (type) = 0;
     }
 
   /* now change all the remaining unknown pointers
@@ -398,7 +426,6 @@ pointerTypes (sym_link * ptr, sym_link * type)
        DCL_TYPE (type) = port->unqualified_pointer;
       type = type->next;
     }
-
 }
 
 /*------------------------------------------------------------------*/
@@ -471,8 +498,6 @@ addDecl (symbol * sym, int type, sym_link * p)
          sym->etype = sym->etype->next = newLink (SPECIFIER);
        }
       SPEC_SCLS (sym->etype) = SPEC_SCLS (DCL_TSPEC (p));
-      SPEC_CONST (sym->etype) = SPEC_CONST (DCL_TSPEC (p));
-      SPEC_VOLATILE (sym->etype) = SPEC_VOLATILE (DCL_TSPEC (p));
       DCL_TSPEC (p) = NULL;
     }
 
@@ -754,8 +779,9 @@ getSize (sym_link * p)
        case V_LABEL:
          return 0;
        case V_SBIT:
-         return BITSIZE;
        case V_BIT:
+         return BITSIZE;
+       case V_BITFIELD:
          return ((SPEC_BLEN (p) / 8) + (SPEC_BLEN (p) % 8 ? 1 : 0));
        default:
          return 0;
@@ -818,8 +844,9 @@ bitsForType (sym_link * p)
        case V_LABEL:
          return 0;
        case V_SBIT:
-         return 1;
        case V_BIT:
+         return 1;
+       case V_BITFIELD:
          return SPEC_BLEN (p);
        default:
          return 0;
@@ -1001,7 +1028,7 @@ funcInChain (sym_link * lnk)
 }
 
 /*------------------------------------------------------------------*/
-/* structElemType - returns the type info of a sturct member        */
+/* structElemType - returns the type info of a struct member        */
 /*------------------------------------------------------------------*/
 sym_link *
 structElemType (sym_link * stype, value * id)
@@ -1021,6 +1048,10 @@ structElemType (sym_link * stype, value * id)
            etype = getSpec (type);
            SPEC_SCLS (etype) = (SPEC_SCLS (petype) == S_REGISTER ?
                                 SPEC_SCLS (etype) : SPEC_SCLS (petype));
+            if (IS_SPEC (type))
+              SPEC_CONST (type) |= SPEC_CONST (stype);
+            else
+              DCL_PTR_CONST (type) |= SPEC_CONST (stype);
            return type;
          }
        fields = fields->next;
@@ -1066,55 +1097,88 @@ compStructSize (int su, structdef * sdef)
 
        /* create the internal name for this variable */
        SNPRINTF (loop->rname, sizeof(loop->rname), "_%s", loop->name);
-       loop->offset = (su == UNION ? sum = 0 : sum);
+       if (su == UNION) {
+           sum = 0;
+           bitOffset = 0;
+       }
        SPEC_VOLATILE (loop->etype) |= (su == UNION ? 1 : 0);
 
        /* if this is a bit field  */
        if (loop->bitVar) {
 
            /* change it to a unsigned bit */
-           SPEC_NOUN (loop->etype) = V_BIT;
+           SPEC_NOUN (loop->etype) = V_BITFIELD;
            SPEC_USIGN (loop->etype) = 1;
-           /* check if this fit into the remaining   */
-           /* bits of this byte else align it to the */
-           /* next byte boundary                     */
-           if ((SPEC_BLEN (loop->etype) = loop->bitVar) <= (8 - bitOffset)) {
-               SPEC_BSTR (loop->etype) = bitOffset;
-               if ((bitOffset += (loop->bitVar % 8)) == 8)
-                   sum++;
+           SPEC_BLEN (loop->etype) = loop->bitVar;
+
+           if (loop->bitVar == BITVAR_PAD) {
+               /* A zero length bitfield forces padding */
+               SPEC_BSTR (loop->etype) = bitOffset;
+               SPEC_BLEN (loop->etype) = 0;
+               bitOffset = 8;
+               loop->offset = sum;
            }
-           else /* does not fit */ {
-               bitOffset = 0;
-               SPEC_BSTR (loop->etype) = bitOffset;
-               sum += (loop->bitVar / 8);
-               bitOffset += (loop->bitVar % 8);
-           }
-           /* if this is the last field then pad */
-           if (!loop->next && bitOffset && bitOffset != 8) {
-               bitOffset = 0;
-               sum++;
+           else {
+               if (bitOffset == 8) {
+                   bitOffset = 0;
+                   sum++;
+               }
+               /* check if this fit into the remaining   */
+               /* bits of this byte else align it to the */
+               /* next byte boundary                     */
+               if (loop->bitVar <= (8 - bitOffset)) {
+                   /* fits into current byte */
+                   loop->offset = sum;
+                   SPEC_BSTR (loop->etype) = bitOffset;
+                   bitOffset += loop->bitVar;
+               }
+               else if (!bitOffset) {
+                   /* does not fit, but is already byte aligned */
+                   loop->offset = sum;
+                   SPEC_BSTR (loop->etype) = bitOffset;
+                   bitOffset += loop->bitVar;
+               } 
+               else {
+                   /* does not fit; need to realign first */
+                   sum++;
+                   loop->offset = (su == UNION ? sum = 0 : sum);
+                   bitOffset = 0;
+                   SPEC_BSTR (loop->etype) = bitOffset;
+                   bitOffset += loop->bitVar;
+               }
+               while (bitOffset>8) {
+                   bitOffset -= 8;
+                   sum++;
+               } 
            }
        }
        else {
+           /* This is a non-bit field. Make sure we are */
+           /* byte aligned first */
+           if (bitOffset) {
+               sum++;
+               loop->offset = (su == UNION ? sum = 0 : sum);
+               bitOffset = 0;
+           }
+           loop->offset = sum;
            checkDecl (loop, 1);
            sum += getSize (loop->type);
        }
 
        loop = loop->next;
 
-       /* if this is not a bitfield but the */
-       /* previous one was and did not take */
-       /* the whole byte then pad the rest  */
-       if ((loop && !loop->bitVar) && bitOffset) {
-           bitOffset = 0;
-           sum++;
-       }
-
        /* if union then size = sizeof larget field */
-       if (su == UNION)
+       if (su == UNION) {
+           /* For UNION, round up after each field */
+           sum += ((bitOffset+7)/8);
            usum = max (usum, sum);
+       }
 
     }
+    
+    /* For STRUCT, round up after all fields processed */
+    if (su != UNION)
+       sum += ((bitOffset+7)/8);
 
     return (su == UNION ? usum : sum);
 }
@@ -1125,11 +1189,13 @@ compStructSize (int su, structdef * sdef)
 static void 
 checkSClass (symbol * sym, int isProto)
 {
+  sym_link *t;
+  
   if (getenv("DEBUG_SANITY")) {
     fprintf (stderr, "checkSClass: %s \n", sym->name);
   }
   
-  /* type is literal can happen foe enums change
+  /* type is literal can happen for enums change
      to auto */
   if (SPEC_SCLS (sym->etype) == S_LITERAL && !SPEC_ENUM (sym->etype))
     SPEC_SCLS (sym->etype) = S_AUTO;
@@ -1152,24 +1218,46 @@ checkSClass (symbol * sym, int isProto)
     if (IS_ABSOLUTE (sym->etype))
       SPEC_VOLATILE (sym->etype) = 1;
   
+  /* If code memory is read only, then pointers to code memory */
+  /* implicitly point to constants -- make this explicit       */
+  t = sym->type;
+  while (t && t->next) {
+    if (IS_CODEPTR(t) && port->mem.code_ro) {
+      if (IS_SPEC(t->next)) {
+        SPEC_CONST (t->next) = 1;
+      } else {
+        DCL_PTR_CONST (t->next) = 1;
+      }
+    }
+    t = t->next;
+  }
 
   /* global variables declared const put into code */
   /* if no other storage class specified */
   if (sym->level == 0 &&
-      SPEC_CONST (sym->etype) &&
       SPEC_SCLS(sym->etype) == S_FIXED &&
       !IS_FUNC(sym->type)) {
-    SPEC_SCLS (sym->etype) = S_CODE;
+    /* find the first non-array link */
+    t = sym->type;
+    while (IS_ARRAY(t))
+      t = t->next;
+    if (IS_CONSTANT (t)) {
+      SPEC_SCLS (sym->etype) = S_CODE;
+    }
   }
 
   /* global variable in code space is a constant */
   if (sym->level == 0 &&
       SPEC_SCLS (sym->etype) == S_CODE &&
       port->mem.code_ro) {
-    if (IS_SPEC(sym->type)) {
-      SPEC_CONST (sym->type) = 1;
+    /* find the first non-array link */
+    t = sym->type;
+    while (IS_ARRAY(t))
+      t = t->next;
+    if (IS_SPEC(t)) {
+      SPEC_CONST (t) = 1;
     } else {
-      DCL_PTR_CONST (sym->type) = 1;
+      DCL_PTR_CONST (t) = 1;
     }
   }
 
@@ -1192,7 +1280,7 @@ checkSClass (symbol * sym, int isProto)
       sym->ival = NULL;
     }
 
-  /* if this is an atomatic symbol */
+  /* if this is an automatic symbol */
   if (sym->level && (options.stackAuto || reentrant)) {
     if ((SPEC_SCLS (sym->etype) == S_AUTO ||
         SPEC_SCLS (sym->etype) == S_FIXED ||
@@ -1223,6 +1311,7 @@ checkSClass (symbol * sym, int isProto)
   if ((IS_ARRAY (sym->type) || IS_PTR (sym->type)) &&
       (SPEC_NOUN (sym->etype) == V_BIT ||
        SPEC_NOUN (sym->etype) == V_SBIT ||
+       SPEC_NOUN (sym->etype) == V_BITFIELD ||
        SPEC_SCLS (sym->etype) == S_SFR))
     werror (E_BIT_ARRAY, sym->name);
 
@@ -1414,15 +1503,18 @@ computeType (sym_link * type1, sym_link * type2)
     rType = copyLinkChain (type2);
 
   reType = getSpec (rType);
+#if 0
+  if (SPEC_NOUN (reType) == V_CHAR)
+    SPEC_NOUN (reType) = V_INT;
+#endif
 
   /* if either of them unsigned but not val then make this unsigned */
-  if (((!IS_LITERAL(type1) && SPEC_USIGN (etype1)) || 
-       (!IS_LITERAL(type2) && SPEC_USIGN (etype2))) && 
+  if ((SPEC_USIGN (etype1) || SPEC_USIGN (etype2)) &&
       !IS_FLOAT (reType))
     SPEC_USIGN (reType) = 1;
   else
     SPEC_USIGN (reType) = 0;
-  
+
   /* if result is a literal then make not so */
   if (IS_LITERAL (reType))
     SPEC_SCLS (reType) = S_REGISTER;
@@ -1433,7 +1525,7 @@ computeType (sym_link * type1, sym_link * type2)
 /*--------------------------------------------------------------------*/
 /* compareType - will do type check return 1 if match, -1 if castable */
 /*--------------------------------------------------------------------*/
-int 
+int
 compareType (sym_link * dest, sym_link * src)
 {
   if (!dest && !src)
@@ -1530,17 +1622,18 @@ compareType (sym_link * dest, sym_link * src)
 /*------------------------------------------------------------------*/
 /* inCalleeSaveList - return 1 if found in callee save list          */
 /*------------------------------------------------------------------*/
-bool 
-inCalleeSaveList (char *s)
+static int
+calleeCmp(void *p1, void *p2)
 {
-  int i;
-
-  if (options.all_callee_saves) return 1;
-  for (i = 0; options.calleeSaves[i]; i++)
-    if (strcmp (options.calleeSaves[i], s) == 0)
-      return 1;
+  return (strcmp((char *)p1, (char *)(p2)) == 0);
+}
 
-  return 0;
+bool
+inCalleeSaveList(char *s)
+{
+  if (options.all_callee_saves)
+    return 1;
+  return isinSetWith(options.calleeSavesSet, s, calleeCmp);
 }
 
 /*-----------------------------------------------------------------*/
@@ -1682,6 +1775,7 @@ checkFunction (symbol * sym, symbol *csym)
       werror(E_PARAM_NAME_OMITTED, sym->name, argCnt);
     }
   }
+  argCnt--;
 
   if (!csym && !(csym = findSym (SymbolTab, sym, sym->name)))
     return 1;                  /* not defined nothing more to check  */
@@ -1715,6 +1809,17 @@ checkFunction (symbol * sym, symbol *csym)
     {
       werror (E_PREV_DEF_CONFLICT, csym->name, "_naked");
     }
+  
+  /* Really, reentrant should match regardless of argCnt, but     */
+  /* this breaks some existing code (the fp lib functions). If    */
+  /* the first argument is always passed the same way, this       */
+  /* lax checking is ok (but may not be true for in future ports) */
+  if (IFFUNC_ISREENT (csym->type) != IFFUNC_ISREENT (sym->type)
+      && argCnt>1)
+    {
+      //printf("argCnt = %d\n",argCnt);
+      werror (E_PREV_DEF_CONFLICT, csym->name, "reentrant");
+    }
 
   /* compare expected args with actual args */
   exargs = FUNC_ARGS(csym->type);
@@ -1951,6 +2056,7 @@ void
 printTypeChain (sym_link * start, FILE * of)
 {
   int nlr = 0;
+  value *args;
   sym_link * type, * search;
   STORAGE_CLASS scls;
 
@@ -1972,7 +2078,10 @@ printTypeChain (sym_link * start, FILE * of)
 
   for (type = start; type && type->next; type = type->next)
     ;
-  scls=SPEC_SCLS(type);
+  if (IS_SPEC (type))
+    scls=SPEC_SCLS(type);
+  else
+    scls=0;
   while (type)
     {
       if (type==start) {
@@ -2010,6 +2119,15 @@ printTypeChain (sym_link * start, FILE * of)
              fprintf (of, "function %s %s", 
                       (IFFUNC_ISBUILTIN(type) ? "__builtin__" : " "),
                       (IFFUNC_ISJAVANATIVE(type) ? "_JavaNative" : " "));
+             fprintf (of, "( ");
+             for (args = FUNC_ARGS(type); 
+                  args; 
+                  args=args->next) {
+               printTypeChain(args->type, of);
+               if (args->next)
+                 fprintf(of, ", ");
+             }
+             fprintf (of, ") ");
              break;
            case GPOINTER:
              fprintf (of, "generic* ");
@@ -2033,7 +2151,7 @@ printTypeChain (sym_link * start, FILE * of)
              fprintf (of, "pdata* ");
              break;
            case UPOINTER:
-             fprintf (of, "unkown* ");
+             fprintf (of, "unknown* ");
              break;
            case ARRAY:
              if (DCL_ELEM(type)) {
@@ -2081,7 +2199,11 @@ printTypeChain (sym_link * start, FILE * of)
              break;
 
            case V_BIT:
-             fprintf (of, "bit {%d,%d}", SPEC_BSTR (type), SPEC_BLEN (type));
+             fprintf (of, "bit");
+             break;
+
+           case V_BITFIELD:
+             fprintf (of, "bitfield {%d,%d}", SPEC_BSTR (type), SPEC_BLEN (type));
              break;
 
            case V_DOUBLE:
@@ -2104,6 +2226,176 @@ printTypeChain (sym_link * start, FILE * of)
     fprintf (of, "\n");
 }
 
+/*--------------------------------------------------------------------*/
+/* printTypeChainRaw - prints the type chain in human readable form   */
+/*                     in the raw data structure ordering             */
+/*--------------------------------------------------------------------*/
+void
+printTypeChainRaw (sym_link * start, FILE * of)
+{
+  int nlr = 0;
+  value *args;
+  sym_link * type;
+
+  if (!of)
+    {
+      of = stdout;
+      nlr = 1;
+    }
+
+  if (start==NULL) {
+    fprintf (of, "void");
+    return;
+  }
+
+  type = start;
+  
+  while (type)
+    {
+      if (IS_DECL (type))
+       {
+         if (!IS_FUNC(type)) {
+           if (DCL_PTR_VOLATILE (type)) {
+             fprintf (of, "volatile-");
+           }
+           if (DCL_PTR_CONST (type)) {
+             fprintf (of, "const-");
+           }
+         }
+         switch (DCL_TYPE (type))
+           {
+           case FUNCTION:
+             fprintf (of, "function %s %s", 
+                      (IFFUNC_ISBUILTIN(type) ? "__builtin__" : " "),
+                      (IFFUNC_ISJAVANATIVE(type) ? "_JavaNative" : " "));
+             fprintf (of, "( ");
+             for (args = FUNC_ARGS(type); 
+                  args; 
+                  args=args->next) {
+               printTypeChain(args->type, of);
+               if (args->next)
+                 fprintf(of, ", ");
+             }
+             fprintf (of, ") ");
+             break;
+           case GPOINTER:
+             fprintf (of, "generic* ");
+             break;
+           case CPOINTER:
+             fprintf (of, "code* ");
+             break;
+           case FPOINTER:
+             fprintf (of, "xdata* ");
+             break;
+           case EEPPOINTER:
+             fprintf (of, "eeprom* ");
+             break;
+           case POINTER:
+             fprintf (of, "near* ");
+             break;
+           case IPOINTER:
+             fprintf (of, "idata* ");
+             break;
+           case PPOINTER:
+             fprintf (of, "pdata* ");
+             break;
+           case UPOINTER:
+             fprintf (of, "unknown* ");
+             break;
+           case ARRAY:
+             if (DCL_ELEM(type)) {
+               fprintf (of, "[%d] ", DCL_ELEM(type));
+             } else {
+               fprintf (of, "[] ");
+             }
+             break;
+           }
+          if (DCL_TSPEC(type))
+            {
+              fprintf (of, "{");
+              printTypeChainRaw(DCL_TSPEC(type), of);
+              fprintf (of, "}");
+            }
+       }
+      else if (IS_SPEC (type))
+       {
+       switch (SPEC_SCLS (type)) 
+         {
+         case S_DATA: fprintf (of, "data-"); break;
+         case S_XDATA: fprintf (of, "xdata-"); break;
+         case S_SFR: fprintf (of, "sfr-"); break;
+         case S_SBIT: fprintf (of, "sbit-"); break;
+         case S_CODE: fprintf (of, "code-"); break;
+         case S_IDATA: fprintf (of, "idata-"); break;
+         case S_PDATA: fprintf (of, "pdata-"); break;
+         case S_LITERAL: fprintf (of, "literal-"); break;
+         case S_STACK: fprintf (of, "stack-"); break;
+         case S_XSTACK: fprintf (of, "xstack-"); break;
+         case S_BIT: fprintf (of, "bit-"); break;
+         case S_EEPROM: fprintf (of, "eeprom-"); break;
+         default: break;
+         }
+         if (SPEC_VOLATILE (type))
+           fprintf (of, "volatile-");
+         if (SPEC_CONST (type))
+           fprintf (of, "const-");
+         if (SPEC_USIGN (type))
+           fprintf (of, "unsigned-");
+         switch (SPEC_NOUN (type))
+           {
+           case V_INT:
+             if (IS_LONG (type))
+               fprintf (of, "long-");
+             fprintf (of, "int");
+             break;
+
+           case V_CHAR:
+             fprintf (of, "char");
+             break;
+
+           case V_VOID:
+             fprintf (of, "void");
+             break;
+
+           case V_FLOAT:
+             fprintf (of, "float");
+             break;
+
+           case V_STRUCT:
+             fprintf (of, "struct %s", SPEC_STRUCT (type)->tag);
+             break;
+
+           case V_SBIT:
+             fprintf (of, "sbit");
+             break;
+
+           case V_BIT:
+             fprintf (of, "bit");
+             break;
+
+           case V_BITFIELD:
+             fprintf (of, "bitfield {%d,%d}", SPEC_BSTR (type), SPEC_BLEN (type));
+             break;
+
+           case V_DOUBLE:
+             fprintf (of, "double");
+             break;
+
+           default:
+             fprintf (of, "unknown type");
+             break;
+           }
+       }
+      else
+        fprintf (of, "NOT_SPEC_OR_DECL");
+      type = type->next;
+      if (type)
+       fputc (' ', of);
+    }
+  if (nlr)
+    fprintf (of, "\n");
+}
+
 
 /*-----------------------------------------------------------------*/
 /* powof2 - returns power of two for the number if number is pow 2 */
@@ -2350,13 +2642,14 @@ initCSupport ()
        }
     }
 
+/*
   for (muldivmod = 0; muldivmod < 3; muldivmod++)
     {
       for (bwd = 0; bwd < 3; bwd++)
        {
          for (su = 0; su < 2; su++)
            {
-             SNPRINTF (buffer, sizeof(buffer), 
+             SNPRINTF (buffer, sizeof(buffer),
                        "_%s%s%s",
                       smuldivmod[muldivmod],
                       ssu[su],
@@ -2367,13 +2660,66 @@ initCSupport ()
        }
     }
 
+  muluint() and mulsint() resp. mululong() and mulslong() return the same result.
+  Therefore they've been merged into mulint() and mullong().
+*/
+
+  for (bwd = 0; bwd < 3; bwd++)
+    {
+      for (su = 0; su < 2; su++)
+       {
+         for (muldivmod = 1; muldivmod < 3; muldivmod++)
+           {
+             /* div and mod */
+             SNPRINTF (buffer, sizeof(buffer),
+                       "_%s%s%s",
+                      smuldivmod[muldivmod],
+                      ssu[su],
+                      sbwd[bwd]);
+             __muldiv[muldivmod][bwd][su] = funcOfType (_mangleFunctionName(buffer), __multypes[bwd][su], __multypes[bwd][su], 2, options.intlong_rent);
+             FUNC_NONBANKED (__muldiv[muldivmod][bwd][su]->type) = 1;
+           }
+       }
+    }
+  /* mul only */
+  muldivmod = 0;
+  /* byte */
+  bwd = 0;
+  for (su = 0; su < 2; su++)
+    {
+      /* muluchar and mulschar are still separate functions, because e.g. the z80
+         port is sign/zero-extending to int before calling mulint() */
+      SNPRINTF (buffer, sizeof(buffer),
+               "_%s%s%s",
+               smuldivmod[muldivmod],
+               ssu[su],
+               sbwd[bwd]);
+      __muldiv[muldivmod][bwd][su] = funcOfType (_mangleFunctionName(buffer), __multypes[bwd][su], __multypes[bwd][su], 2, options.intlong_rent);
+      FUNC_NONBANKED (__muldiv[muldivmod][bwd][su]->type) = 1;
+    }
+  /* signed only */
+  su = 0;
+  /* word and doubleword */
+  for (bwd = 1; bwd < 3; bwd++)
+    {
+      /* mul, int/long */
+      SNPRINTF (buffer, sizeof(buffer),
+               "_%s%s",
+               smuldivmod[muldivmod],
+               sbwd[bwd]);
+      __muldiv[muldivmod][bwd][0] = funcOfType (_mangleFunctionName(buffer), __multypes[bwd][su], __multypes[bwd][su], 2, options.intlong_rent);
+      FUNC_NONBANKED (__muldiv[muldivmod][bwd][0]->type) = 1;
+      /* signed = unsigned */
+      __muldiv[muldivmod][bwd][1] = __muldiv[muldivmod][bwd][0];
+    }
+
   for (rlrr = 0; rlrr < 2; rlrr++)
     {
       for (bwd = 0; bwd < 3; bwd++)
        {
          for (su = 0; su < 2; su++)
            {
-             SNPRINTF (buffer, sizeof(buffer), 
+             SNPRINTF (buffer, sizeof(buffer),
                        "_%s%s%s",
                       srlrr[rlrr],
                       ssu[su],