[llvm] [JumpThreading] Do not unfold select if block has address taken and used (PR #135106)

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Thu May 1 03:56:43 PDT 2025


================
@@ -665,6 +665,52 @@ if.end:
   ret i32 %v1
 }
 
+; Do not unfold select when parent block address is taken and used
+define i32 @ba_unfold(i1 %cond, i32 %arg) {
+; CHECK-LABEL: @ba_unfold(
+; CHECK: B4:
+; CHECK-NEXT:   [[P:%.*]] = phi i1 [ true, [[B1:%.*]] ], [ [[COND_NOT:%.*]], [[LOOPEXIT:%.*]] ]
+; CHECK-NEXT:   [[OFFSET:%.*]] = select i1 [[P]], i64 8, i64 16
+; CHECK-NEXT:   [[ADDR_I:%.*]] = add i64 [[OFFSET]], ptrtoint (ptr blockaddress(@ba_unfold, %B4) to i64)
+;
+entry:
+  br label %B1
+
+B1:
+  br i1 %cond, label %B2, label %B4
+
+B2:
+  br label %while.body
+
+B3:
+  %new_i = add nuw nsw i32 1, %i
+  %exitcond = icmp eq i32 %new_i, 5
+  br i1 %exitcond, label %loopexit, label %while.body
+
+while.body:
+  %i = phi i32 [ 0, %B2 ], [ %new_i, %B3 ]
+  %xor = xor i32 %i, 16
+  %cmp = icmp eq i32 %xor, %arg
+  br i1 %cmp, label %B3, label %loopexit
+
+loopexit:
+  %cond.not = xor i1 %cmp, true
+  br label %B4
+
+B4:
+  %p = phi i1 [true, %B1], [ %cond.not, %loopexit ]
+  %offset = select i1 %p, i64 8, i64 16
+  %addr_i = add i64 %offset, ptrtoint (ptr blockaddress(@ba_unfold, %B4) to i64)
----------------
nikic wrote:

This test doesn't have UB anymore, but I believe the transform is correct:

> This value only has defined behavior when used as an operand to the ‘[indirectbr](https://llvm.org/docs/LangRef.html#i-indirectbr)’ or for comparisons against null. Pointer equality tests between labels addresses results in undefined behavior — though, again, comparison against null is ok, and no label is equal to the null pointer. This may be passed around as an opaque pointer sized value as long as the bits are not inspected. This allows ptrtoint and arithmetic to be performed on these values so long as the original value is reconstituted before the indirectbr instruction.

Note that the use of blockaddress does not prevent the removal of the block being referenced, if it's not an indirectbr target.

Can you share any context on how you end up with this blockaddress in the first place? This suggests you are using block labels for something other than computed goto, which is not supported. Is this a `({ __label__ __here; __here: (unsigned long)&&__here; })` "get the instruction pointer" style usage perhaps, or is it something else?

https://github.com/llvm/llvm-project/pull/135106


More information about the llvm-commits mailing list