Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Clang] Constant value is corrupted when optimization is enabled #108010

Open
gerekon opened this issue Sep 10, 2024 · 1 comment
Open

[Clang] Constant value is corrupted when optimization is enabled #108010

gerekon opened this issue Sep 10, 2024 · 1 comment

Comments

@gerekon
Copy link

gerekon commented Sep 10, 2024

Hi guys!

I came across strange behavior. With enabled optimization when inlined function is provided with the address of external symbol (as argument) the two least bits of the constant used inside that function get cleared. Looks like optimizer assumes that address of external symbol should be aligned to 4-bytes and therefore aligns constatnt value used for bitwise AND operation with that address.
This is target independent behavior (checked this for X86, ARM and RISCV targets) because constant has aligned value already in IR.

Narrowed it down to simple program. IR can be generated with clang --target=arm-none-eabi test.c -Og -S -emit-llvm
After debugging it a bit I found that consntant changes its value when test function gets actually inlined at some step in InstCombinePass or InlinerPass optimization pass. Problem exists at any level of optimization except -O0 (bcs in this case function is not inlined).

Bad case C code

#define SOC_MMU_LINEAR_ADDR_MASK              0x1FFFFFF

extern int _instruction_reserved_end;

__attribute__((always_inline))
static inline unsigned int test(unsigned int vaddr)
{
    return vaddr & SOC_MMU_LINEAR_ADDR_MASK;
}
int main()
{
    // this produces inlined IR with wrongly aligned constant value 0x1FFFFFC
    volatile unsigned int tmp = test((unsigned int)&_instruction_reserved_end);
    return tmp;
}

IR for bad case. Note %2 = and i32 ptrtoint (ptr @_instruction_reserved_end to i32), 33554428

; Function Attrs: nofree norecurse nounwind memory(inaccessiblemem: readwrite)
define dso_local i32 @main() local_unnamed_addr #0 {
  %1 = alloca i32, align 4
  call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %1)
  %2 = and i32 ptrtoint (ptr @_instruction_reserved_end to i32), 33554428
  store volatile i32 %2, ptr %1, align 4, !tbaa !4
  %3 = load volatile i32, ptr %1, align 4, !tbaa !4
  call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %1)
  ret i32 %3
}

Good case C code

#define SOC_MMU_LINEAR_ADDR_MASK              0x1FFFFFF

extern int _instruction_reserved_end;

__attribute__((always_inline))
static inline unsigned int test(unsigned int vaddr)
{
    return vaddr & SOC_MMU_LINEAR_ADDR_MASK;
}

int main()
{
    // code below produces inlined IR with correct constant value 0x1FFFFFF
    volatile unsigned int addr = (unsigned int)&_instruction_reserved_end;
    volatile unsigned int tmp = test(addr);
    return tmp;
}

IR for good case. Note %4 = and i32 %3, 33554431

; Function Attrs: nofree norecurse nounwind memory(inaccessiblemem: readwrite)
define dso_local i32 @main() local_unnamed_addr #0 {
  %1 = alloca i32, align 4
  %2 = alloca i32, align 4
  call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %1)
  store volatile i32 ptrtoint (ptr @_instruction_reserved_end to i32), ptr %1, align 4, !tbaa !4
  call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %2)
  %3 = load volatile i32, ptr %1, align 4, !tbaa !4
  %4 = and i32 %3, 33554431
  store volatile i32 %4, ptr %2, align 4, !tbaa !4
  %5 = load volatile i32, ptr %2, align 4, !tbaa !4
  call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %2)
  call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %1)
  ret i32 %5
}
@github-actions github-actions bot added the clang Clang issues not falling into any other category label Sep 10, 2024
@EugeneZelenko EugeneZelenko added llvm:optimizations and removed clang Clang issues not falling into any other category labels Sep 10, 2024
@gerekon
Copy link
Author

gerekon commented Sep 10, 2024

Ok. Looks like the behavior can be considered as normal because external symbol is declared as int. For char problem does not appear.

In my case extern int _instruction_reserved_end; is the declaration of linker symbol which can be unaligned to 4-bytes. Changing it to char solves the problem. So issue can be closed if this behavior is expected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants