--- /dev/null
+; RUN: llvm-reduce --abort-on-invalid-reduction --delta-passes=instruction-flags --test FileCheck --test-arg --check-prefixes=INTERESTING,CHECK --test-arg %s --test-arg --input-file %s -o %t
+; RUN: FileCheck -check-prefixes=RESULT,CHECK %s < %t
+
+; CHECK-LABEL: @add_nuw_nsw_none(
+; INTERESTING: = add
+; RESULT: add i32
+define i32 @add_nuw_nsw_none(i32 %a, i32 %b) {
+ %op = add nuw nsw i32 %a, %b
+ ret i32 %op
+}
+
+; CHECK-LABEL: @add_nuw_nsw_keep_nuw(
+; INTERESTING: nuw
+; RESULT: add nuw i32
+define i32 @add_nuw_nsw_keep_nuw(i32 %a, i32 %b) {
+ %op = add nuw nsw i32 %a, %b
+ ret i32 %op
+}
+
+; CHECK-LABEL: @add_nuw_nsw_keep_nsw(
+; INTERESTING: nuw
+; RESULT: add nuw i32
+define i32 @add_nuw_nsw_keep_nsw(i32 %a, i32 %b) {
+ %op = add nuw nsw i32 %a, %b
+ ret i32 %op
+}
+
+; CHECK-LABEL: @add_nuw_keep_nuw(
+; INTERESTING: nuw
+; RESULT: add nuw i32
+define i32 @add_nuw_keep_nuw(i32 %a, i32 %b) {
+ %op = add nuw i32 %a, %b
+ ret i32 %op
+}
+
+; CHECK-LABEL: @add_nsw_keep_nsw(
+; INTERESTING: nsw
+; RESULT: add nsw i32
+define i32 @add_nsw_keep_nsw(i32 %a, i32 %b) {
+ %op = add nsw i32 %a, %b
+ ret i32 %op
+}
+
+; CHECK-LABEL: @ashr_exact_drop(
+; INTERESTING: = ashr
+; RESULT: ashr i32
+define i32 @ashr_exact_drop(i32 %a, i32 %b) {
+ %op = ashr exact i32 %a, %b
+ ret i32 %op
+}
+
+; CHECK-LABEL: @ashr_exact_keep(
+; INTERESTING: exact
+; RESULT: ashr exact i32
+define i32 @ashr_exact_keep(i32 %a, i32 %b) {
+ %op = ashr exact i32 %a, %b
+ ret i32 %op
+}
+
+; CHECK-LABEL: @getelementptr_inbounds_drop(
+; INTERESTING: getelementptr
+; RESULT: getelementptr i32, ptr %a, i64 %b
+define ptr @getelementptr_inbounds_drop(ptr %a, i64 %b) {
+ %op = getelementptr inbounds i32, ptr %a, i64 %b
+ ret ptr %op
+}
+
+; CHECK-LABEL: @getelementptr_inbounds_keep(
+; INTERESTING: inbounds
+; RESULT: getelementptr inbounds i32, ptr %a, i64 %b
+define ptr @getelementptr_inbounds_keep(ptr %a, i64 %b) {
+ %op = getelementptr inbounds i32, ptr %a, i64 %b
+ ret ptr %op
+}
+
+; CHECK-LABEL: @fadd_reassoc_none(
+; INTERESTING: = fadd
+; RESULT: fadd float
+define float @fadd_reassoc_none(float %a, float %b) {
+ %op = fadd reassoc float %a, %b
+ ret float %op
+}
+
+; CHECK-LABEL: @fadd_reassoc_keep(
+; INTERESTING: fadd reassoc
+; RESULT: fadd reassoc float
+define float @fadd_reassoc_keep(float %a, float %b) {
+ %op = fadd reassoc float %a, %b
+ ret float %op
+}
+
+; CHECK-LABEL: @fadd_nnan_none(
+; INTERESTING: = fadd
+; RESULT: fadd float
+define float @fadd_nnan_none(float %a, float %b) {
+ %op = fadd nnan float %a, %b
+ ret float %op
+}
+
+; CHECK-LABEL: @fadd_nnan_keep(
+; INTERESTING: fadd nnan
+; RESULT: fadd nnan float
+define float @fadd_nnan_keep(float %a, float %b) {
+ %op = fadd nnan float %a, %b
+ ret float %op
+}
+
+; CHECK-LABEL: @fadd_ninf_none(
+; INTERESTING: = fadd
+; RESULT: fadd float
+define float @fadd_ninf_none(float %a, float %b) {
+ %op = fadd ninf float %a, %b
+ ret float %op
+}
+
+; CHECK-LABEL: @fadd_ninf_keep(
+; INTERESTING: fadd ninf
+; RESULT: fadd ninf float
+define float @fadd_ninf_keep(float %a, float %b) {
+ %op = fadd ninf float %a, %b
+ ret float %op
+}
+
+; CHECK-LABEL: @fadd_nsz_none(
+; INTERESTING: = fadd
+; RESULT: fadd float
+define float @fadd_nsz_none(float %a, float %b) {
+ %op = fadd nsz float %a, %b
+ ret float %op
+}
+
+; CHECK-LABEL: @fadd_nsz_keep(
+; INTERESTING: fadd nsz
+; RESULT: fadd nsz float
+define float @fadd_nsz_keep(float %a, float %b) {
+ %op = fadd nsz float %a, %b
+ ret float %op
+}
+
+; CHECK-LABEL: @fadd_arcp_none(
+; INTERESTING: = fadd
+; RESULT: fadd float
+define float @fadd_arcp_none(float %a, float %b) {
+ %op = fadd arcp float %a, %b
+ ret float %op
+}
+
+; CHECK-LABEL: @fadd_arcp_keep(
+; INTERESTING: fadd arcp
+; RESULT: fadd arcp float
+define float @fadd_arcp_keep(float %a, float %b) {
+ %op = fadd arcp float %a, %b
+ ret float %op
+}
+
+; CHECK-LABEL: @fadd_contract_none(
+; INTERESTING: = fadd
+; RESULT: fadd float
+define float @fadd_contract_none(float %a, float %b) {
+ %op = fadd contract float %a, %b
+ ret float %op
+}
+
+; CHECK-LABEL: @fadd_contract_keep(
+; INTERESTING: fadd contract
+; RESULT: fadd contract float
+define float @fadd_contract_keep(float %a, float %b) {
+ %op = fadd contract float %a, %b
+ ret float %op
+}
+
+; CHECK-LABEL: @fadd_afn_none(
+; INTERESTING: = fadd
+; RESULT: fadd float
+define float @fadd_afn_none(float %a, float %b) {
+ %op = fadd afn float %a, %b
+ ret float %op
+}
+
+; CHECK-LABEL: @fadd_afn_keep(
+; INTERESTING: fadd afn
+; RESULT: fadd afn float
+define float @fadd_afn_keep(float %a, float %b) {
+ %op = fadd afn float %a, %b
+ ret float %op
+}
+
+; CHECK-LABEL: @fadd_fast_none(
+; INTERESTING: = fadd
+; RESULT: fadd float
+define float @fadd_fast_none(float %a, float %b) {
+ %op = fadd fast float %a, %b
+ ret float %op
+}
+
+; CHECK-LABEL: @fadd_nnan_ninf_keep_nnan(
+; INTERESTING: nnan
+; RESULT: fadd nnan float
+define float @fadd_nnan_ninf_keep_nnan(float %a, float %b) {
+ %op = fadd nnan ninf float %a, %b
+ ret float %op
+}
--- /dev/null
+//===- ReduceInstructionFlags.cpp - Specialized Delta Pass ----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Try to remove optimization flags on instructions
+//
+//===----------------------------------------------------------------------===//
+
+#include "ReduceInstructionFlags.h"
+#include "Delta.h"
+#include "llvm/IR/InstIterator.h"
+#include "llvm/IR/Instruction.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Operator.h"
+
+static void reduceFlagsInModule(Oracle &O, Module &Mod) {
+ for (Function &F : Mod) {
+ for (Instruction &I : instructions(F)) {
+ if (auto *OBO = dyn_cast<OverflowingBinaryOperator>(&I)) {
+ if (OBO->hasNoSignedWrap() && !O.shouldKeep())
+ I.setHasNoSignedWrap(false);
+ if (OBO->hasNoUnsignedWrap() && !O.shouldKeep())
+ I.setHasNoUnsignedWrap(false);
+ } else if (auto *PE = dyn_cast<PossiblyExactOperator>(&I)) {
+ if (PE->isExact() && !O.shouldKeep())
+ I.setIsExact(false);
+ } else if (auto *GEP = dyn_cast<GetElementPtrInst>(&I)) {
+ if (GEP->isInBounds() && !O.shouldKeep())
+ GEP->setIsInBounds(false);
+ } else if (auto *FPOp = dyn_cast<FPMathOperator>(&I)) {
+ FastMathFlags Flags = FPOp->getFastMathFlags();
+
+ if (Flags.allowReassoc() && !O.shouldKeep())
+ Flags.setAllowReassoc(false);
+
+ if (Flags.noNaNs() && !O.shouldKeep())
+ Flags.setNoNaNs(false);
+
+ if (Flags.noInfs() && !O.shouldKeep())
+ Flags.setNoInfs(false);
+
+ if (Flags.noSignedZeros() && !O.shouldKeep())
+ Flags.setNoSignedZeros(false);
+
+ if (Flags.allowReciprocal() && !O.shouldKeep())
+ Flags.setAllowReciprocal(false);
+
+ if (Flags.allowContract() && !O.shouldKeep())
+ Flags.setAllowContract(false);
+
+ if (Flags.approxFunc() && !O.shouldKeep())
+ Flags.setApproxFunc(false);
+
+ I.copyFastMathFlags(Flags);
+ }
+ }
+ }
+}
+
+void llvm::reduceInstructionFlagsDeltaPass(TestRunner &Test) {
+ runDeltaPass(Test, reduceFlagsInModule, "Reducing Instruction Flags");
+}