Skip to content

BitcodeReader does not merge same incoming pairs in PHI node when inserts phi constexpr block #139245

@edgankin

Description

@edgankin

When inserting phi constexpr block it simply replaces predecessor block with newly created block, however the phi node may contain multiple entries for the predecessor block, but only one should be left since there is only one edge from newly create phi constexpr block to the successor block.

The problem can be easily reproduced when LLVM18+ tries to read binary bitcode compiled by LLVM17, because in LLVM18 most constant expressions were removed.

The problem can be reproduced with the attached bug.ll:

@.str = private unnamed_addr constant [5 x i8] c"WORK\00", align 1

define ptr @bug(i8 noundef %0)  {
  switch i8 %0, label %2 [
      i8 1, label %5
      i8 2, label %5
      i8 3, label %3
      i8 0, label %4
    ]

  2:                                                ; preds = %1
    unreachable

  3:                                                ; preds = %1
    br label %5

  4:                                                ; preds = %1
    br label %5

  5:                                                ; preds = %4, %3, %1, %1

    %6 = phi ptr [ inttoptr (i64 111 to ptr), %4 ], [ inttoptr (i64 222 to ptr), %3 ], [ inttoptr (i64 or (i64 sub (i64 ptrtoint (ptr @.str to i64), i64 32), i64 -9223372036854775808) to ptr), %1 ], [ inttoptr (i64 or (i64 sub (i64 ptrtoint (ptr @.str to i64), i64 32), i64 -9223372036854775808) to ptr), %1 ]
    ret ptr %6
}

Compile it to binary bitcode with LLVM17:
/opt/llvm@17/bin/llvm-as bug.ll -o bug17.bc
(bug17.bc is also attached)

The resulted bitcode file will be improperly read by LLVM18+:

/opt/llvm@19/bin/opt -passes="verify" bug17.bc
PHINode should have one entry for each predecessor of its parent basic block!
  %6 = phi ptr [ inttoptr (i64 111 to ptr), %4 ], [ inttoptr (i64 222 to ptr), %3 ], [ %constexpr1, %phi.constexpr ], [ %constexpr1, %phi.constexpr ]
/opt/llvm@19/bin/opt: bug17.bc: error: input module is broken!

Produced IR:

define ptr @bug(i8 noundef %0) {
  switch i8 %0, label %2 [
    i8 1, label %phi.constexpr
    i8 2, label %phi.constexpr
    i8 3, label %3
    i8 0, label %4
  ]

2:                                                ; preds = %1
  unreachable

3:                                                ; preds = %1
  br label %5

4:                                                ; preds = %1
  br label %5

phi.constexpr:                                    ; preds = %1, %1
  %constexpr = or i64 sub (i64 ptrtoint (ptr @.str to i64), i64 32), -9223372036854775808
  %constexpr1 = inttoptr i64 %constexpr to ptr
  br label %5

5:                                                ; preds = %phi.constexpr, %4, %3
  %6 = phi ptr [ inttoptr (i64 111 to ptr), %4 ], [ inttoptr (i64 222 to ptr), %3 ], [ %constexpr1, %phi.constexpr ], [ %constexpr1, %phi.constexpr ]
  ret ptr %6
}

Note that phi.constexpr appears twice in the PHI node, while it should appear only once.

bug.zip

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions