Peter Collingbourne 191af6c254
Add llvm.cond.loop intrinsic.
The llvm.cond.loop intrinsic is semantically equivalent to a conditional
branch conditioned on ``pred`` to a basic block consisting only of an
unconditional branch to itself. Unlike such a branch, it is guaranteed
to use specific instructions. This allows an interrupt handler or
other introspection mechanism to straightforwardly detect whether
the program is currently spinning in the infinite loop and possibly
terminate the program if so. The intent is that this intrinsic may
be used as a more efficient alternative to a conditional branch to
a call to ``llvm.trap`` in circumstances where the loop detection
is guaranteed to be present. This construct has been experimentally
determined to be executed more efficiently (when the branch is not taken)
than a conditional branch to a trap instruction on AMD and older Intel
microarchitectures, and is also more code size efficient by avoiding the
need to emit a trap instruction and possibly a long branch instruction.

On i386 and x86_64, the infinite loop is guaranteed to consist of a short
conditional branch instruction that branches to itself. Specifically,
the first byte of the instruction will be between 0x70 and 0x7F, and
the second byte will be 0xFE.

Part of this RFC:
https://discourse.llvm.org/t/rfc-optimizing-conditional-traps/89456

Reviewers: arsenm, RKSimon, fmayer, vitalybuka

Pull Request: https://github.com/llvm/llvm-project/pull/177686
2026-02-06 17:11:15 -08:00

51 lines
1.2 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
; RUN: llc < %s -mtriple=x86_64 | FileCheck %s
define void @f1(i64 %a, i64 %b) {
; CHECK-LABEL: f1:
; CHECK: # %bb.0:
; CHECK-NEXT: cmpq %rsi, %rdi
; CHECK-NEXT: .Ltmp0:
; CHECK-NEXT: jb .Ltmp0
; CHECK-NEXT: retq
%cmp = icmp ult i64 %a, %b
call void @llvm.cond.loop(i1 %cmp)
ret void
}
define void @f2() {
; CHECK-LABEL: f2:
; CHECK: # %bb.0:
; CHECK-NEXT: movb $1, %al
; CHECK-NEXT: testb %al, %al
; CHECK-NEXT: .Ltmp1:
; CHECK-NEXT: jne .Ltmp1
; CHECK-NEXT: retq
call void @llvm.cond.loop(i1 true)
ret void
}
define void @f3(i1 %p) {
; CHECK-LABEL: f3:
; CHECK: # %bb.0:
; CHECK-NEXT: testb $1, %dil
; CHECK-NEXT: .Ltmp2:
; CHECK-NEXT: jne .Ltmp2
; CHECK-NEXT: retq
call void @llvm.cond.loop(i1 %p)
ret void
}
define void @f4(i32 %a, i32 %b) {
; CHECK-LABEL: f4:
; CHECK: # %bb.0:
; CHECK-NEXT: addl %esi, %edi
; CHECK-NEXT: .Ltmp3:
; CHECK-NEXT: jo .Ltmp3
; CHECK-NEXT: retq
%add = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %a, i32 %b)
%overflow = extractvalue { i32, i1 } %add, 1
tail call void @llvm.cond.loop(i1 %overflow)
ret void
}