[llvm-branch-commits] [llvm] release/23.x: [X86][CCMP] Fix invalid CCMP emission (#211161) (PR #211494)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu Jul 23 01:26:48 PDT 2026
https://github.com/llvmbot created https://github.com/llvm/llvm-project/pull/211494
Backport 45b30651cf94ddb32676550cca7ddd3f6a5e66e0
Requested by: @phoebewang
>From 749b726691c71209922580bb3a8df95d085ec8b7 Mon Sep 17 00:00:00 2001
From: Phoebe Wang <phoebe.wang at intel.com>
Date: Thu, 23 Jul 2026 11:43:18 +0800
Subject: [PATCH] [X86][CCMP] Fix invalid CCMP emission (#211161)
This patch ports AArch64's negation-aware conjunction algorithm to fix
invalid CCMP emission when OR nested inside an AND.
Example: https://godbolt.org/z/ave7f61hK
Before the change, the above case returns 5 rather the 9 when CCMP
enabled.
Assisted-by: Claude Opus 4.8
(cherry picked from commit 45b30651cf94ddb32676550cca7ddd3f6a5e66e0)
---
llvm/lib/Target/X86/X86ISelLowering.cpp | 197 +++++++++++++++++-------
llvm/test/CodeGen/X86/apx/ccmp.ll | 78 +++++++---
2 files changed, 199 insertions(+), 76 deletions(-)
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index f651dba18be8f..76a474c496fe7 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -25494,52 +25494,102 @@ static SDValue LowerSELECTWithCmpZero(SDValue CmpVal, SDValue LHS, SDValue RHS,
return SDValue();
}
-// Return true if Val is an integer ISD::SETCC or an AND/OR tree thereof,
-// suitable for lowering to a CCMP chain.
-static bool canEmitConjunctionForCCMP(SDValue Val) {
- unsigned Opc = Val.getOpcode();
- if (Opc == ISD::SETCC)
- return Val.getOperand(0).getSimpleValueType().isInteger();
- if (Opc == ISD::AND && Val.hasOneUse())
- return canEmitConjunctionForCCMP(Val.getOperand(0)) &&
- canEmitConjunctionForCCMP(Val.getOperand(1));
- // For OR, at least one operand must be a leaf SETCC so the DCF of the right
- // CCMP is unambiguous.
- if (Opc == ISD::OR && Val.hasOneUse())
- return (Val.getOperand(0).getOpcode() == ISD::SETCC ||
- Val.getOperand(1).getOpcode() == ISD::SETCC) &&
- canEmitConjunctionForCCMP(Val.getOperand(0)) &&
- canEmitConjunctionForCCMP(Val.getOperand(1));
+/// Returns true if \p Val is a tree of integer AND/OR/SETCC operations that
+/// can be expressed as a CCMP conjunction. This mirrors AArch64's
+/// canEmitConjunction and tracks the negation bookkeeping required to lower
+/// arbitrarily nested AND/OR trees (e.g. AND(cc, OR(cc, cc))) correctly.
+/// \param CanNegate Set to true if the whole sub-tree can be negated just by
+/// inverting the conditions on the SETCC leaves.
+/// \param MustBeFirst Set to true if this sub-tree needs to be negated but
+/// cannot be negated naturally, so it must be emitted first.
+/// \param WillNegate True when the result of this sub-expression must be
+/// negated (i.e. the outer expression is an OR).
+static bool canEmitConjunctionForCCMP(SDValue Val, bool &CanNegate,
+ bool &MustBeFirst, bool WillNegate,
+ unsigned Depth = 0) {
+ if (!Val.hasOneUse())
+ return false;
+ unsigned Opcode = Val.getOpcode();
+ if (Opcode == ISD::SETCC) {
+ if (!Val.getOperand(0).getSimpleValueType().isInteger())
+ return false;
+ CanNegate = true;
+ MustBeFirst = false;
+ return true;
+ }
+ // Protect against exponential runtime and stack overflow.
+ if (Depth > 6)
+ return false;
+ if (Opcode == ISD::AND || Opcode == ISD::OR) {
+ bool IsOR = Opcode == ISD::OR;
+ SDValue O0 = Val.getOperand(0);
+ SDValue O1 = Val.getOperand(1);
+ bool CanNegateL, MustBeFirstL;
+ if (!canEmitConjunctionForCCMP(O0, CanNegateL, MustBeFirstL, IsOR,
+ Depth + 1))
+ return false;
+ bool CanNegateR, MustBeFirstR;
+ if (!canEmitConjunctionForCCMP(O1, CanNegateR, MustBeFirstR, IsOR,
+ Depth + 1))
+ return false;
+
+ if (MustBeFirstL && MustBeFirstR)
+ return false;
+
+ if (IsOR) {
+ // For an OR we need to be able to naturally negate at least one side or
+ // we cannot do the transformation at all.
+ if (!CanNegateL && !CanNegateR)
+ return false;
+ // If the OR's result will be negated and both leaves can be negated
+ // naturally, then this sub-tree as a whole negates naturally.
+ CanNegate = WillNegate && CanNegateL && CanNegateR;
+ MustBeFirst = !CanNegate;
+ } else {
+ assert(Opcode == ISD::AND && "Must be OR or AND");
+ // We cannot naturally negate an AND operation.
+ CanNegate = false;
+ MustBeFirst = MustBeFirstL || MustBeFirstR;
+ }
+ return true;
+ }
return false;
}
-// Recursively emit a CCMP chain for an AND/OR tree of integer SETCCs.
-// CCOp: incoming flags value (null for the first/root comparison)
-// Predicate: condition under which CCOp was produced (COND_INVALID at root)
-// OutCC: set to the condition code to test after the whole chain
-// Returns the flags-producing node (SUB or CCMP).
-//
-// AND(cc1, cc2): emit cc1 first; CCMP(cc2) fires when cc1 is true.
-// SrcCC = cc1, DCF forces cc2 false when cc1 is false.
-// OR(cc1, cc2): emit cc1 first; CCMP(cc2) fires when cc1 is false.
-// SrcCC = ~cc1, DCF forces cc2 true when cc1 is true.
+/// Emit a conjunction or disjunction tree as a CMP followed by a chain of
+/// CCMP operations. Mirrors AArch64's emitConjunctionRec.
+/// CCOp: incoming flags value (null for the first/root comparison)
+/// Predicate: condition under which CCOp was produced (COND_INVALID at root)
+/// Negate: true if this sub-tree should be negated by inverting the
+/// conditions on its SETCC leaves
+/// OutCC: set to the condition code to test after the whole chain
+/// Returns the flags-producing node (CMP/SUB or CCMP).
static SDValue emitConjunctionForCCMPRec(SDValue Val, X86::CondCode &OutCC,
- SDValue CCOp, X86::CondCode Predicate,
+ bool Negate, SDValue CCOp,
+ X86::CondCode Predicate,
SelectionDAG &DAG,
const X86Subtarget &Subtarget) {
SDLoc DL(Val);
- if (Val.getOpcode() == ISD::SETCC) {
+ unsigned Opcode = Val.getOpcode();
+ if (Opcode == ISD::SETCC) {
SDValue LHS = Val.getOperand(0), RHS = Val.getOperand(1);
ISD::CondCode CC = cast<CondCodeSDNode>(Val.getOperand(2))->get();
+ if (Negate)
+ CC = ISD::getSetCCInverse(CC, LHS.getValueType());
X86::CondCode X86CC = TranslateX86CC(CC, DL, /*IsFP=*/false, LHS, RHS, DAG);
assert(X86CC != X86::COND_INVALID);
OutCC = X86CC;
SDValue Flags = EmitCmp(LHS, RHS, X86CC, DL, DAG, Subtarget);
+ // Produce a normal comparison if we are first in the chain.
if (!CCOp)
return Flags;
+ // Otherwise produce a CCMP. The CCMP executes (and updates EFLAGS) only
+ // when Predicate holds; when it is skipped it forces the default condition
+ // flags, which must make OutCC evaluate to false. That default is encoded
+ // from the opposite of X86CC.
SDNode *FlagsNode = Flags.getNode();
X86::CondCode DCFCode = X86::GetOppositeBranchCondition(X86CC);
SDValue CFlags = DAG.getTargetConstant(
@@ -25549,47 +25599,78 @@ static SDValue emitConjunctionForCCMPRec(SDValue Val, X86::CondCode &OutCC,
{FlagsNode->getOperand(0), FlagsNode->getOperand(1),
CFlags, SrcCC, CCOp});
}
+ assert(Val.hasOneUse() && "Valid conjunction/disjunction tree");
- bool IsOR = Val.getOpcode() == ISD::OR;
- SDValue LHS = Val.getOperand(0), RHS = Val.getOperand(1);
-
- // For OR, the right subtree must be a leaf SETCC so its DCF unambiguously
- // forces the outcome true when skipped. OR is commutative, so swap if needed.
- if (IsOR && RHS.getOpcode() != ISD::SETCC)
- std::swap(LHS, RHS);
-
- // Emit the left subtree first (provides CCOp for the right subtree's CCMP).
- X86::CondCode LHSCC;
- SDValue CmpL =
- emitConjunctionForCCMPRec(LHS, LHSCC, CCOp, Predicate, DAG, Subtarget);
+ bool IsOR = Opcode == ISD::OR;
- // For AND: right CCMP fires when left is true, SrcCC = LHSCC.
- // For OR: right CCMP fires when left is false, SrcCC = !LHSCC.
- X86::CondCode NextPred =
- IsOR ? X86::GetOppositeBranchCondition(LHSCC) : LHSCC;
+ SDValue LHS = Val.getOperand(0);
+ bool CanNegateL, MustBeFirstL;
+ bool ValidL = canEmitConjunctionForCCMP(LHS, CanNegateL, MustBeFirstL, IsOR);
+ assert(ValidL && "Valid conjunction/disjunction tree");
+ (void)ValidL;
- SDValue CmpR =
- emitConjunctionForCCMPRec(RHS, OutCC, CmpL, NextPred, DAG, Subtarget);
+ SDValue RHS = Val.getOperand(1);
+ bool CanNegateR, MustBeFirstR;
+ bool ValidR = canEmitConjunctionForCCMP(RHS, CanNegateR, MustBeFirstR, IsOR);
+ assert(ValidR && "Valid conjunction/disjunction tree");
+ (void)ValidR;
- // For OR, patch the DCF of the right leaf's CCMP to force OutCC TRUE when
- // the CCMP is skipped (i.e. when the left condition was already true).
- if (IsOR && CmpR.getOpcode() == X86ISD::CCMP) {
- SDValue CFlags = DAG.getTargetConstant(
- X86::getCCMPCondFlagsFromCondCode(OutCC), DL, MVT::i8);
- CmpR = DAG.getNode(X86ISD::CCMP, DL, MVT::i32,
- {CmpR.getOperand(0), CmpR.getOperand(1), CFlags,
- CmpR.getOperand(3), CmpR.getOperand(4)});
+ // Swap the sub-tree that must come first to the right side.
+ if (MustBeFirstL) {
+ assert(!MustBeFirstR && "Valid conjunction/disjunction tree");
+ std::swap(LHS, RHS);
+ std::swap(CanNegateL, CanNegateR);
+ std::swap(MustBeFirstL, MustBeFirstR);
}
- return CmpR;
+
+ bool NegateR, NegateAfterR, NegateL, NegateAfterAll;
+ if (IsOR) {
+ // Swap the sub-tree that we can negate naturally to the left.
+ if (!CanNegateL) {
+ assert(CanNegateR && "at least one side must be negatable");
+ assert(!MustBeFirstR && "invalid conjunction/disjunction tree");
+ assert(!Negate);
+ std::swap(LHS, RHS);
+ NegateR = false;
+ NegateAfterR = true;
+ } else {
+ // Negate the left sub-tree if possible, otherwise negate the result.
+ NegateR = CanNegateR;
+ NegateAfterR = !CanNegateR;
+ }
+ NegateL = true;
+ NegateAfterAll = !Negate;
+ } else {
+ assert(Opcode == ISD::AND && "Valid conjunction/disjunction tree");
+ assert(!Negate && "Valid conjunction/disjunction tree");
+ NegateL = false;
+ NegateR = false;
+ NegateAfterR = false;
+ NegateAfterAll = false;
+ }
+
+ // Emit sub-trees. The right sub-tree is emitted first so its flags feed the
+ // left sub-tree's CCMP chain.
+ X86::CondCode RHSCC;
+ SDValue CmpR = emitConjunctionForCCMPRec(RHS, RHSCC, NegateR, CCOp, Predicate,
+ DAG, Subtarget);
+ if (NegateAfterR)
+ RHSCC = X86::GetOppositeBranchCondition(RHSCC);
+ SDValue CmpL = emitConjunctionForCCMPRec(LHS, OutCC, NegateL, CmpR, RHSCC,
+ DAG, Subtarget);
+ if (NegateAfterAll)
+ OutCC = X86::GetOppositeBranchCondition(OutCC);
+ return CmpL;
}
static SDValue emitConjunctionForCCMP(SDValue Val, X86::CondCode &OutCC,
SelectionDAG &DAG,
const X86Subtarget &Subtarget) {
- if (!canEmitConjunctionForCCMP(Val))
+ bool DummyCanNegate, DummyMustBeFirst;
+ if (!canEmitConjunctionForCCMP(Val, DummyCanNegate, DummyMustBeFirst, false))
return SDValue();
- return emitConjunctionForCCMPRec(Val, OutCC, SDValue(), X86::COND_INVALID,
- DAG, Subtarget);
+ return emitConjunctionForCCMPRec(Val, OutCC, /*Negate=*/false, SDValue(),
+ X86::COND_INVALID, DAG, Subtarget);
}
SDValue X86TargetLowering::LowerSELECT(SDValue Op, SelectionDAG &DAG) const {
diff --git a/llvm/test/CodeGen/X86/apx/ccmp.ll b/llvm/test/CodeGen/X86/apx/ccmp.ll
index 0a696c45eef32..8629b179a1797 100644
--- a/llvm/test/CodeGen/X86/apx/ccmp.ll
+++ b/llvm/test/CodeGen/X86/apx/ccmp.ll
@@ -2103,16 +2103,16 @@ define i32 @ccmp_cmov_and(i32 %a, i32 %b, i32 %c, i32 %d) {
; CHECK-LABEL: ccmp_cmov_and:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: movl %edi, %eax # encoding: [0x89,0xf8]
-; CHECK-NEXT: cmpl %ecx, %esi # encoding: [0x39,0xce]
-; CHECK-NEXT: ccmpnel {dfv=} %edx, %edi # encoding: [0x62,0xf4,0x04,0x05,0x39,0xd7]
-; CHECK-NEXT: cmovll %esi, %eax # encoding: [0x0f,0x4c,0xc6]
+; CHECK-NEXT: cmpl %edx, %edi # encoding: [0x39,0xd7]
+; CHECK-NEXT: ccmpll {dfv=zf} %ecx, %esi # encoding: [0x62,0xf4,0x14,0x0c,0x39,0xce]
+; CHECK-NEXT: cmovnel %esi, %eax # encoding: [0x0f,0x45,0xc6]
; CHECK-NEXT: retq # encoding: [0xc3]
;
; NDD-LABEL: ccmp_cmov_and:
; NDD: # %bb.0: # %entry
-; NDD-NEXT: cmpl %ecx, %esi # encoding: [0x39,0xce]
-; NDD-NEXT: ccmpnel {dfv=} %edx, %edi # encoding: [0x62,0xf4,0x04,0x05,0x39,0xd7]
-; NDD-NEXT: cmovll %esi, %edi, %eax # encoding: [0x62,0xf4,0x7c,0x18,0x4c,0xfe]
+; NDD-NEXT: cmpl %edx, %edi # encoding: [0x39,0xd7]
+; NDD-NEXT: ccmpll {dfv=zf} %ecx, %esi # encoding: [0x62,0xf4,0x14,0x0c,0x39,0xce]
+; NDD-NEXT: cmovnel %esi, %edi, %eax # encoding: [0x62,0xf4,0x7c,0x18,0x45,0xfe]
; NDD-NEXT: retq # encoding: [0xc3]
;
; ZU_COMMON-LABEL: ccmp_cmov_and:
@@ -2136,17 +2136,17 @@ define i32 @ccmp_cmov_and_or(i32 %a, i32 %b, i32 %c, i32 %d) {
; CHECK-LABEL: ccmp_cmov_and_or:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: movl %edi, %eax # encoding: [0x89,0xf8]
-; CHECK-NEXT: cmpl %ecx, %esi # encoding: [0x39,0xce]
-; CHECK-NEXT: ccmpnel {dfv=} %edx, %edi # encoding: [0x62,0xf4,0x04,0x05,0x39,0xd7]
-; CHECK-NEXT: ccmpgel {dfv=} %ecx, %edi # encoding: [0x62,0xf4,0x04,0x0d,0x39,0xcf]
+; CHECK-NEXT: cmpl %edx, %edi # encoding: [0x39,0xd7]
+; CHECK-NEXT: ccmpll {dfv=zf} %ecx, %esi # encoding: [0x62,0xf4,0x14,0x0c,0x39,0xce]
+; CHECK-NEXT: ccmpel {dfv=} %ecx, %edi # encoding: [0x62,0xf4,0x04,0x04,0x39,0xcf]
; CHECK-NEXT: cmovgl %esi, %eax # encoding: [0x0f,0x4f,0xc6]
; CHECK-NEXT: retq # encoding: [0xc3]
;
; NDD-LABEL: ccmp_cmov_and_or:
; NDD: # %bb.0: # %entry
-; NDD-NEXT: cmpl %ecx, %esi # encoding: [0x39,0xce]
-; NDD-NEXT: ccmpnel {dfv=} %edx, %edi # encoding: [0x62,0xf4,0x04,0x05,0x39,0xd7]
-; NDD-NEXT: ccmpgel {dfv=} %ecx, %edi # encoding: [0x62,0xf4,0x04,0x0d,0x39,0xcf]
+; NDD-NEXT: cmpl %edx, %edi # encoding: [0x39,0xd7]
+; NDD-NEXT: ccmpll {dfv=zf} %ecx, %esi # encoding: [0x62,0xf4,0x14,0x0c,0x39,0xce]
+; NDD-NEXT: ccmpel {dfv=} %ecx, %edi # encoding: [0x62,0xf4,0x04,0x04,0x39,0xcf]
; NDD-NEXT: cmovgl %esi, %edi, %eax # encoding: [0x62,0xf4,0x7c,0x18,0x4f,0xfe]
; NDD-NEXT: retq # encoding: [0xc3]
;
@@ -2176,17 +2176,17 @@ define i32 @ccmp_cmov_and_or_c(i32 %a, i32 %b, i32 %c, i32 %d) {
; CHECK-LABEL: ccmp_cmov_and_or_c:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: movl %edi, %eax # encoding: [0x89,0xf8]
-; CHECK-NEXT: cmpl %edx, %edi # encoding: [0x39,0xd7]
-; CHECK-NEXT: ccmpll {dfv=zf} %ecx, %esi # encoding: [0x62,0xf4,0x14,0x0c,0x39,0xce]
-; CHECK-NEXT: ccmpel {dfv=} %ecx, %edi # encoding: [0x62,0xf4,0x04,0x04,0x39,0xcf]
+; CHECK-NEXT: cmpl %ecx, %esi # encoding: [0x39,0xce]
+; CHECK-NEXT: ccmpnel {dfv=} %edx, %edi # encoding: [0x62,0xf4,0x04,0x05,0x39,0xd7]
+; CHECK-NEXT: ccmpgel {dfv=} %ecx, %edi # encoding: [0x62,0xf4,0x04,0x0d,0x39,0xcf]
; CHECK-NEXT: cmovgl %esi, %eax # encoding: [0x0f,0x4f,0xc6]
; CHECK-NEXT: retq # encoding: [0xc3]
;
; NDD-LABEL: ccmp_cmov_and_or_c:
; NDD: # %bb.0: # %entry
-; NDD-NEXT: cmpl %edx, %edi # encoding: [0x39,0xd7]
-; NDD-NEXT: ccmpll {dfv=zf} %ecx, %esi # encoding: [0x62,0xf4,0x14,0x0c,0x39,0xce]
-; NDD-NEXT: ccmpel {dfv=} %ecx, %edi # encoding: [0x62,0xf4,0x04,0x04,0x39,0xcf]
+; NDD-NEXT: cmpl %ecx, %esi # encoding: [0x39,0xce]
+; NDD-NEXT: ccmpnel {dfv=} %edx, %edi # encoding: [0x62,0xf4,0x04,0x05,0x39,0xd7]
+; NDD-NEXT: ccmpgel {dfv=} %ecx, %edi # encoding: [0x62,0xf4,0x04,0x0d,0x39,0xcf]
; NDD-NEXT: cmovgl %esi, %edi, %eax # encoding: [0x62,0xf4,0x7c,0x18,0x4f,0xfe]
; NDD-NEXT: retq # encoding: [0xc3]
;
@@ -2210,5 +2210,47 @@ entry:
ret i32 %sel
}
+; (b != d) && ((a < c) || (a > d)): OR nested inside an AND. This shape needs
+; the De Morgan negation bookkeeping in the CCMP conjunction emitter; a naive
+; emitter miscompiles it (the inner OR wrongly forces the result true when the
+; AND's left operand is false).
+define i32 @ccmp_cmov_and_of_or(i32 %a, i32 %b, i32 %c, i32 %d) {
+; CHECK-LABEL: ccmp_cmov_and_of_or:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: movl %edi, %eax # encoding: [0x89,0xf8]
+; CHECK-NEXT: cmpl %ecx, %edi # encoding: [0x39,0xcf]
+; CHECK-NEXT: ccmplel {dfv=sf} %edx, %edi # encoding: [0x62,0xf4,0x24,0x0e,0x39,0xd7]
+; CHECK-NEXT: ccmpll {dfv=zf} %ecx, %esi # encoding: [0x62,0xf4,0x14,0x0c,0x39,0xce]
+; CHECK-NEXT: cmovnel %esi, %eax # encoding: [0x0f,0x45,0xc6]
+; CHECK-NEXT: retq # encoding: [0xc3]
+;
+; NDD-LABEL: ccmp_cmov_and_of_or:
+; NDD: # %bb.0: # %entry
+; NDD-NEXT: cmpl %ecx, %edi # encoding: [0x39,0xcf]
+; NDD-NEXT: ccmplel {dfv=sf} %edx, %edi # encoding: [0x62,0xf4,0x24,0x0e,0x39,0xd7]
+; NDD-NEXT: ccmpll {dfv=zf} %ecx, %esi # encoding: [0x62,0xf4,0x14,0x0c,0x39,0xce]
+; NDD-NEXT: cmovnel %esi, %edi, %eax # encoding: [0x62,0xf4,0x7c,0x18,0x45,0xfe]
+; NDD-NEXT: retq # encoding: [0xc3]
+;
+; ZU_COMMON-LABEL: ccmp_cmov_and_of_or:
+; ZU_COMMON: # %bb.0: # %entry
+; ZU_COMMON-NEXT: cmpl %ecx, %edi # encoding: [0x39,0xcf]
+; ZU_COMMON-NEXT: movl %edi, %eax # encoding: [0x89,0xf8]
+; ZU_COMMON-NEXT: cmovgl %esi, %eax # encoding: [0x0f,0x4f,0xc6]
+; ZU_COMMON-NEXT: cmpl %edx, %edi # encoding: [0x39,0xd7]
+; ZU_COMMON-NEXT: cmovll %esi, %eax # encoding: [0x0f,0x4c,0xc6]
+; ZU_COMMON-NEXT: cmpl %ecx, %esi # encoding: [0x39,0xce]
+; ZU_COMMON-NEXT: cmovel %edi, %eax # encoding: [0x0f,0x44,0xc7]
+; ZU_COMMON-NEXT: retq # encoding: [0xc3]
+entry:
+ %cmp1 = icmp ne i32 %b, %d
+ %cmp2 = icmp slt i32 %a, %c
+ %cmp3 = icmp sgt i32 %a, %d
+ %or = or i1 %cmp2, %cmp3
+ %and = and i1 %cmp1, %or
+ %sel = select i1 %and, i32 %b, i32 %a
+ ret i32 %sel
+}
+
declare dso_local void @foo(...)
declare {i64, i1} @llvm.ssub.with.overflow.i64(i64, i64) nounwind readnone
More information about the llvm-branch-commits
mailing list