On 21/11/2016 16:56, Andre Przywara wrote:
Hi Alex,

On 21/11/16 15:42, Alexander Graf wrote:


On 20/11/2016 15:56, Andre Przywara wrote:
tiny-printf does not know about the "l" modifier so far, which breaks
the crash dump on AArch64, because it uses %lx to print the registers.
Add an easy way of handling longs correctly.

Signed-off-by: Andre Przywara <andre.przyw...@arm.com>
---
 lib/tiny-printf.c | 43 +++++++++++++++++++++++++++++++++----------
 1 file changed, 33 insertions(+), 10 deletions(-)

diff --git a/lib/tiny-printf.c b/lib/tiny-printf.c
index 30ac759..b01099d 100644
--- a/lib/tiny-printf.c
+++ b/lib/tiny-printf.c
@@ -38,8 +38,8 @@ static void out_dgt(struct printf_info *info, char dgt)
     info->zs = 1;
 }

-static void div_out(struct printf_info *info, unsigned int *num,
-            unsigned int div)
+static void div_out(struct printf_info *info, unsigned long *num,
+            unsigned long div)
 {
     unsigned char dgt = 0;

@@ -56,9 +56,9 @@ int _vprintf(struct printf_info *info, const char
*fmt, va_list va)
 {
     char ch;
     char *p;
-    unsigned int num;
+    unsigned long num;
     char buf[12];
-    unsigned int div;
+    unsigned long div;

     while ((ch = *(fmt++))) {
         if (ch != '%') {
@@ -66,8 +66,12 @@ int _vprintf(struct printf_info *info, const char
*fmt, va_list va)
         } else {
             bool lz = false;
             int width = 0;
+            bool islong = false;

             ch = *(fmt++);
+            if (ch == '-')
+                ch = *(fmt++);
+

What does this do? I don't see '-' mentioned in the patch description.

Argh, apparently the comment in the commit message got lost during a
patch reshuffle. Sorry, will re-add it.

We need it because some SPL printf uses '-', just ignoring it here seems
fine for SPL purposes though.


             if (ch == '0') {
                 ch = *(fmt++);
                 lz = 1;
@@ -80,6 +84,11 @@ int _vprintf(struct printf_info *info, const char
*fmt, va_list va)
                     ch = *fmt++;
                 }
             }
+            if (ch == 'l') {
+                ch = *(fmt++);
+                islong = true;
+            }
+
             info->bf = buf;
             p = info->bf;
             info->zs = 0;
@@ -89,24 +98,38 @@ int _vprintf(struct printf_info *info, const char
*fmt, va_list va)
                 goto abort;
             case 'u':
             case 'd':
-                num = va_arg(va, unsigned int);
-                if (ch == 'd' && (int)num < 0) {
-                    num = -(int)num;
+                div = 1000000000;
+                if (islong) {

Check here if sizeof(long) > 4, so that the whole branch gets optimized
away on 32bit.

Good idea.

+                    num = va_arg(va, unsigned long);
+                    if (sizeof(long) > 4)
+                        div *= div * 10;
+                } else {
+                    num = va_arg(va, unsigned int);
+                }
+
+                if (ch == 'd' && (long)num < 0) {
+                    num = -(long)num;

Num is a long now and before. So if you have a 32bit signed input, it
will sign extend incorrectly here. You need an additional check

  if (islong)
    num = -(long)num;
  else
    num = -(int)num;

Let's hope the compiler on 32bit is smart enough to know that it can
combine those two cases :).

                     out(info, '-');
                 }
                 if (!num) {
                     out_dgt(info, 0);
                 } else {
-                    for (div = 1000000000; div; div /= 10)
+                    for (; div; div /= 10)

Any particular reason for that change?

This algorithm so far only cared for 32-bit values, so it set the start
divider to 1E9. This is not sufficient for 64-bit longs in AA64.
So I compute div above, depending on the actual size of long.

Ah, I missed the div *= up there. Sure, then it makes sense. Btw, have you checked that the compiler is smart enough to do constant propagation here? Multiplications can be very expensive.


Alex
_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to