Skip to content

Incorrect code generated for float llvm.maximum/minimum intrinsics #77805

Closed
@danilaml

Description

@danilaml

I believe this change introduced a bug preventing correct handing of signed zeroes in certain cases.

This check

  if (Op->getOpcode() == ISD::BUILD_VECTOR ||
      Op->getOpcode() == ISD::SPLAT_VECTOR) {
    for (const SDValue &OpVal : Op->op_values()) {
      if (OpVal.isUndef())
        return false;
      if (auto *C = dyn_cast<ConstantFPSDNode>(OpVal))
        if (C->isZero())
          return false;
    }
    return true;
  }

Returns true by default, marking most BUILD/SPLAT vectors as known non-zeroes preventing the negative zero check generation.

See this example: https://godbolt.org/z/Yh5oE916v

target triple = "x86_64-unknown-linux-gnu"

declare float @llvm.maximum.f32(float, float)
declare <8 x float> @llvm.maximum.v8f32(<8 x float>,<8 x float>)

define <8 x float> @foo(float %a, <8 x float> %vec) #0 {
entry:
  %splatinsert = insertelement <8 x float> poison, float %a, i64 0
  %splat = shufflevector <8 x float> %splatinsert, <8 x float> poison, <8 x i32> zeroinitializer
  %res = call nnan noundef <8 x float> @llvm.maximum.v8f32(<8 x float> %splat, <8 x float> %vec)
  ret <8 x float> %res
}

attributes #0 = { "target-cpu"="haswell" }

I believe the check should look something like

  if (Op->getOpcode() == ISD::BUILD_VECTOR ||
      Op->getOpcode() == ISD::SPLAT_VECTOR) {
    return llvm::all_of(Op->op_values(), [](const SDValue &OpVal){
      if (auto *C = dyn_cast<ConstantFPSDNode>(OpVal))
        return !C->isZero();
      return false;
    });
  }

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions