[U-Boot] [PATCH 05/24] SPL: tiny-printf: add "l" modifier
Alexander Graf
agraf at suse.de
Mon Nov 21 17:05:38 CET 2016
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.przywara at 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
More information about the U-Boot
mailing list