Skip to content

Conversation

@markram1729
Copy link
Contributor

@markram1729 markram1729 commented Sep 27, 2025

Resolves Partial #8918
// Folder for
maj_inv(x, !x, y) -> y
maj_inv(x, x, y) -> x
maj_inv(x, 0, 1) -> x

Comment on lines 126 to 140
// If i and j are constant.
if (auto c1 = getConstant(i)) {
if (auto c2 = getConstant(j)) {
// If both constants are equal, we can fold.
if (*c1 == *c2) {
// auto value = cast<IntegerAttr>(getInputs()[i]).getValue();
// return IntegerAttr::get(IntegerType::get(getContext(),
// value.getBitWidth()),value);
return IntegerAttr::get(getType(), *c1);
}
// If constants are complementary, we can fold.
if (*c1 == ~*c2)
return getOperand(k);
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This block would be dead as two constants are already handled.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes handled !

auto width = inputs[0].getBitWidth();
APInt result(width, 0);

// is every input of same width ?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay!

// x 1 1
if (inputValues.size() == 2) {
if (inputValues[0] != inputValues[1])
return {};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's pessimistic. If two constants are same you can return constants, if they are complement you can return third variable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true , resolved !

if (isInverted(i) != isInverted(j)) {
return getOperand(k);
}
return getOperand(i);
Copy link
Member

@uenoku uenoku Sep 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a my bug but it's necessary to check if operand i is inverted. Could you fix it as well?

Copy link
Contributor Author

@markram1729 markram1729 Sep 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @uenoku ,
if operand(i) is inverted , should i return {} ?

I can't return with inverted operand(i) , let canonicalise handle it !

Copy link
Member

@uenoku uenoku left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

}
}
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you need to return {} here as evaluate expects same operands. Also evaluate expects uninverted values so the current code is not correct.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes , it is handled now

Thank you for pointing out

@markram1729 markram1729 force-pushed the exaSynthMaj branch 5 times, most recently from 7c95602 to 272d8e2 Compare September 29, 2025 07:24
@markram1729 markram1729 marked this pull request as ready for review September 29, 2025 07:26
@markram1729 markram1729 requested a review from uenoku September 29, 2025 15:02
@markram1729
Copy link
Contributor Author

Hi @uenoku , Can you please check if this resolves the folding issue ?

assert(inputs.size() == getNumOperands() &&
"Number of inputs must match number of operands");

if (inputs.size() == 3) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you keep the previous implementation? evaluate is meant to evaluate the op based on input values so it's necessary to look at inversion.

Copy link
Member

@uenoku uenoku left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for delayed review!

IntegerType::get(getContext(), inputValues[0].getBitWidth()),
inputValues[0]);
else
return getOperand(index); // fix if it is a Inverted
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you check the inversion?

Comment on lines 115 to 117
// Pattern match following cases:
// maj_inv(x, x, y) -> x
// maj_inv(x, y, not y) -> x
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you keep the canonicalization since folder is essentially a bit weaker?

Comment on lines 70 to 79
SmallVector<APInt, 3> inputValues;
size_t i = 0, index;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you do slightly change the code structure to store non-constant index and check based on the number constants?

Suggested change
SmallVector<APInt, 3> inputValues;
size_t i = 0, index;
SmallVector<APInt, 3> inputValues;
SmallVector<unsigned, 3> nonConstantIndex;
for (auto [i, input] : llvm::enumerate(adaptor.getInputs())) {
auto attr = llvm::dyn_cast_or_null<IntegerAttr>(input);
if (attr)
inputValues.push_back(attr);
else
nonConstantIndex.push_back(i);
}
if (inputValues.size() == getNumINputs())
return IntegerAttr::get(getType(), evaluate(inputValues));
if (getNumOperands() != 3)
return {};
if (nonConstantIndex.size() == 1) {
// Get two constants.
auto idx = nonConstantIndex.front();
auto constIndex1 = (idx+1)%3;
auto constIndex2 = (idx+2)%3;
auto c1 = adaptor.getInputs()[constIndex1];
auto c2 = ...
auto ...;
}

@markram1729 markram1729 marked this pull request as draft October 2, 2025 06:38
@markram1729
Copy link
Contributor Author

Hi @uenoku ,
I have pushed the new changes , I will optimise it more

Can you suggest how can i handle ~x in fold

any way i can return ~x as i can't negate a operand
will canonicalise handle it ? I am returning as return {}

@uenoku
Copy link
Member

uenoku commented Oct 3, 2025

Really thank you for working hard on this 🙇🙇!

Can you suggest how can i handle ~x in fold

Unfortunately we cannot handle it since it's not allowed to create a new operation: https://mlir.llvm.org/docs/Canonicalization/#canonicalizing-with-the-fold-method
So it's necessary to just give up the folding for such cases.

@markram1729
Copy link
Contributor Author

markram1729 commented Oct 3, 2025

Hi @uenoku , can i handle in fold ?

 x x 1 -> x
 x ~x 1 -> 1
 ~x ~x 1 -> ~x

I have commented in the code ,as canoicalisation ishandling it

@markram1729 markram1729 requested a review from uenoku October 3, 2025 06:32
@uenoku
Copy link
Member

uenoku commented Oct 5, 2025

The first two can be implemented in a straightforward way.

For the 3rd one, i realized maybe MLIR folder allows in-place mutation for the op itself, so maybe you can do something like

            (*this)->setOperands({getOperand(k)});
            (*this).setInverted({true});
            return getResult();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants