Skip to content

Higher optimization levels miscompile consecutive i24 subtractions by retaining carry #52

Description

@NinjadenMu

Reproduction:

#include "debug.h"

typedef __INT24_TYPE__ i24;

int main()
{
  volatile int24_t input = 5;
  int24_t foo = input;

  int24_t bar = -foo;
  int24_t quux = -foo + 1;
  dbg_printf("%d", bar);
  dbg_printf("%d", quux);
}

Compiling this under -O0 prints the expected -5, -4, while compiling under -O3 prints -5, -5.

I suspect this is due to the carry bit being retained between computing bar=-foo via sbc 0 foo followed by quux=-foo+1 via sbc 1 foo, which actually computes 1-foo-1 due to the retained carry bit. -O0 avoids this by including or a, a after computing bar.

Should be able to see -O0 clearing the carry flag with or a, a while -O3 doesn't by viewing assembly generated for this:

typedef __INT24_TYPE__ i24;

extern void consume(i24, i24);

void test(i24 foo)
{
  consume(-foo, 1 - foo);
}

On clang version 19.1.0, commit ef28e9c54cd1333a6091ab2ffbd315b465fc5090

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions