Nikita Popov e44b11d9b6 [ValueTracking] Treat branch on undef as UB as well
We were already treating branch on poison as UB, but branch on
undef is also UB. Move the checks into the correct function.

From LangRef for br:

> If ‘cond’ is poison or undef, this instruction has undefined behavior.

From LangRef for switch:

> If ‘value’ is poison or undef, this instruction has undefined behavior.

There is a minor regression in dont-distribute-phi.ll, apparently
we handle that pattern in logical but not bitwise form.
2023-01-02 12:34:23 +01:00

57 lines
2.4 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
; Don't promote around control flow.
define internal i32 @callee(i1 %C, ptr %P) {
; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(argmem: read)
; CHECK-LABEL: define {{[^@]+}}@callee
; CHECK-SAME: (i1 noundef [[C:%.*]], ptr nocapture nofree readonly [[P:%.*]]) #[[ATTR0:[0-9]+]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
; CHECK: T:
; CHECK-NEXT: ret i32 17
; CHECK: F:
; CHECK-NEXT: [[X:%.*]] = load i32, ptr [[P]], align 4
; CHECK-NEXT: ret i32 [[X]]
;
entry:
br i1 %C, label %T, label %F
T:
ret i32 17
F:
%X = load i32, ptr %P
ret i32 %X
}
define i32 @foo(i1 %C, ptr %P) {
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(argmem: read)
; TUNIT-LABEL: define {{[^@]+}}@foo
; TUNIT-SAME: (i1 [[C:%.*]], ptr nocapture nofree readonly [[P:%.*]]) #[[ATTR0]] {
; TUNIT-NEXT: entry:
; TUNIT-NEXT: [[X:%.*]] = call i32 @callee(i1 [[C]], ptr nocapture nofree readonly [[P]]) #[[ATTR1:[0-9]+]]
; TUNIT-NEXT: ret i32 [[X]]
;
; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(argmem: read)
; CGSCC-LABEL: define {{[^@]+}}@foo
; CGSCC-SAME: (i1 noundef [[C:%.*]], ptr nocapture nofree readonly [[P:%.*]]) #[[ATTR1:[0-9]+]] {
; CGSCC-NEXT: entry:
; CGSCC-NEXT: [[X:%.*]] = call i32 @callee(i1 noundef [[C]], ptr nocapture nofree readonly [[P]]) #[[ATTR2:[0-9]+]]
; CGSCC-NEXT: ret i32 [[X]]
;
entry:
%X = call i32 @callee(i1 %C, ptr %P)
ret i32 %X
}
;.
; TUNIT: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind willreturn memory(argmem: read) }
; TUNIT: attributes #[[ATTR1]] = { nofree nosync nounwind willreturn }
;.
; CGSCC: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind willreturn memory(argmem: read) }
; CGSCC: attributes #[[ATTR1]] = { nofree nosync nounwind willreturn memory(argmem: read) }
; CGSCC: attributes #[[ATTR2]] = { willreturn }
;.