Skip to content

Commit aa02b76

Browse files
committed
[X86] Let's improve the expression we dump for vpternlog
Right now, we are printing stuff like: zmm0 = (~zmm0 & zmm1 & mem) | (zmm0 & ~zmm1 & ~mem) | (zmm0 & ~zmm1 & mem) | (zmm0 & zmm1 & ~mem) | (zmm0 & zmm1 & mem) This is not wrong but it sure is verbose and it makes it a bit hard to understand what is going on at a glance. The above expression is equivalent to: zmm0 = zmm0 | (zmm1 & mem) I considered simplifying the expressions on the fly but that gets out of hand very quickly. Quine-McCluskey is not so simple and so fast that it makes a ton of sense for our pretty printer. I quickly played around with some different normal forms and ended up just using this [1] table of functions with some minor post-processing. I made sure that each function is identical to the appropriate BooleanFunction in Mathematica. If the size of these tables ends up mattering for whatever reason there are a few obvious things we could do to save space without undue effort. [1]: https://gist.github.com/dougallj/81a80cd381988466c4e1c4889ecac95b#file-2-x86-base-txt
1 parent c7d4d39 commit aa02b76

16 files changed

+1493
-1251
lines changed

llvm/lib/Target/X86/MCTargetDesc/X86InstComments.cpp

Lines changed: 286 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "llvm/MC/MCInst.h"
2020
#include "llvm/MC/MCInstrInfo.h"
2121
#include "llvm/Support/raw_ostream.h"
22+
#include <string_view>
2223

2324
using namespace llvm;
2425

@@ -622,6 +623,270 @@ static bool printFMAComments(const MCInst *MI, raw_ostream &OS,
622623
return true;
623624
}
624625

626+
// This table is indexed by the imm8 binary function specified in a
627+
// vpternlog{d,q} instruction. The symbols {a,b,c} correspond to the three
628+
// inputs to the binary function. This table was taken from
629+
// https://gist.github.com/dougallj/81a80cd381988466c4e1c4889ecac95b#file-2-x86-base-txt
630+
// with slight massaging.
631+
constexpr StringLiteral TernlogFunctions[] = {
632+
"0",
633+
"~(a | b | c)",
634+
"c & ~(a | b)",
635+
"~(a | b)",
636+
"b & ~(a | c)",
637+
"~(a | c)",
638+
"~a & (b ^ c)",
639+
"~(a | (b & c))",
640+
"b & c & ~a",
641+
"~(a | (b ^ c))",
642+
"c & ~a",
643+
"~a & (c | ~b)",
644+
"b & ~a",
645+
"~a & (b | ~c)",
646+
"~a & (b | c)",
647+
"~a",
648+
"a & ~(b | c)",
649+
"~(b | c)",
650+
"~b & (a ^ c)",
651+
"~((a & c) | b)",
652+
"~c & (a ^ b)",
653+
"~((a & b) | c)",
654+
"a ^ ((a & b) | (b ^ c))",
655+
"(a & (b ^ c)) ^ ~(b & c)",
656+
"(a ^ b) & (a ^ c)",
657+
"~((a & b) | (b ^ c))",
658+
"a ^ ((a & b) | c)",
659+
"(a & c) ^ (c | ~b)",
660+
"a ^ ((a & c) | b)",
661+
"(a & b) ^ (b | ~c)",
662+
"a ^ (b | c)",
663+
"~(a & (b | c))",
664+
"a & c & ~b",
665+
"~(b | (a ^ c))",
666+
"c & ~b",
667+
"~b & (c | ~a)",
668+
"(a ^ b) & (b ^ c)",
669+
"~((a & b) | (a ^ c))",
670+
"b ^ ((a & b) | c)",
671+
"(b & c) ^ (c | ~a)",
672+
"c & (a ^ b)",
673+
"(a | b) ^ ((a & b) | ~c)",
674+
"c & ~(a & b)",
675+
"(c & (a ^ b)) | ~(a | b)",
676+
"(b | c) & (a ^ b)",
677+
"a ^ (b | ~c)",
678+
"(a & b) ^ (b | c)",
679+
"(c & ~b) | ~a",
680+
"a & ~b",
681+
"~b & (a | ~c)",
682+
"~b & (a | c)",
683+
"~b",
684+
"b ^ (a | (b & c))",
685+
"(a & b) ^ (a | ~c)",
686+
"b ^ (a | c)",
687+
"~(b & (a | c))",
688+
"(a | c) & (a ^ b)",
689+
"b ^ (a | ~c)",
690+
"(a & b) ^ (a | c)",
691+
"(c & ~a) | ~b",
692+
"a ^ b",
693+
"~(a | c) | (a ^ b)",
694+
"(c & ~a) | (a ^ b)",
695+
"~(a & b)",
696+
"a & b & ~c",
697+
"~(c | (a ^ b))",
698+
"(a ^ c) & (b ^ c)",
699+
"~((a & c) | (a ^ b))",
700+
"b & ~c",
701+
"~c & (b | ~a)",
702+
"c ^ ((a & c) | b)",
703+
"(b & c) ^ (b | ~a)",
704+
"b & (a ^ c)",
705+
"(a | c) ^ ((a & c) | ~b)",
706+
"(b | c) & (a ^ c)",
707+
"a ^ (c | ~b)",
708+
"b & ~(a & c)",
709+
"(b & (a ^ c)) | ~(a | c)",
710+
"(a & c) ^ (b | c)",
711+
"(b & ~c) | ~a",
712+
"a & ~c",
713+
"~c & (a | ~b)",
714+
"c ^ (a | (b & c))",
715+
"(a & c) ^ (a | ~b)",
716+
"~c & (a | b)",
717+
"~c",
718+
"c ^ (a | b)",
719+
"~(c & (a | b))",
720+
"(a | b) & (a ^ c)",
721+
"c ^ (a | ~b)",
722+
"a ^ c",
723+
"~(a | b) | (a ^ c)",
724+
"(a & c) ^ (a | b)",
725+
"(b & ~a) | ~c",
726+
"(b & ~a) | (a ^ c)",
727+
"~(a & c)",
728+
"a & (b ^ c)",
729+
"~(b ^ c) ^ (a | (b & c))",
730+
"(a | c) & (b ^ c)",
731+
"b ^ (c | ~a)",
732+
"(a | b) & (b ^ c)",
733+
"c ^ (b | ~a)",
734+
"b ^ c",
735+
"~(a | b) | (b ^ c)",
736+
"(a | b) & (c ^ (a & b))",
737+
"b ^ c ^ ~a",
738+
"c ^ (a & b)",
739+
"~(a | b) | (c ^ (a & b))",
740+
"b ^ (a & c)",
741+
"~(a | c) | (b ^ (a & c))",
742+
"(b & ~a) | (b ^ c)",
743+
"~a | (b ^ c)",
744+
"a & ~(b & c)",
745+
"(a & (b ^ c)) | ~(b | c)",
746+
"(b & c) ^ (a | c)",
747+
"(a & ~c) | ~b",
748+
"(b & c) ^ (a | b)",
749+
"(a & ~b) | ~c",
750+
"(a & ~b) | (b ^ c)",
751+
"~(b & c)",
752+
"a ^ (b & c)",
753+
"~(b | c) | (a ^ (b & c))",
754+
"(a & ~b) | (a ^ c)",
755+
"~b | (a ^ c)",
756+
"(a & ~c) | (a ^ b)",
757+
"~c | (a ^ b)",
758+
"(a ^ b) | (a ^ c)",
759+
"~(a & b & c)",
760+
"a & b & c",
761+
"~((a ^ b) | (a ^ c))",
762+
"c & ~(a ^ b)",
763+
"~(a ^ b) & (c | ~a)",
764+
"b & ~(a ^ c)",
765+
"~(a ^ c) & (b | ~a)",
766+
"(b | c) & (a ^ b ^ c)",
767+
"(b & c) ^ ~a",
768+
"b & c",
769+
"~(b ^ c) & (b | ~a)",
770+
"c & (b | ~a)",
771+
"~((b & c) ^ (a | b))",
772+
"b & (c | ~a)",
773+
"~((b & c) ^ (a | c))",
774+
"a ^ ((a ^ b) | (a ^ c))",
775+
"(b & c) | ~a",
776+
"a & ~(b ^ c)",
777+
"~(b ^ c) & (a | ~b)",
778+
"(a | c) & (a ^ b ^ c)",
779+
"(a & c) ^ ~b",
780+
"(a | b) & (a ^ b ^ c)",
781+
"(a & b) ^ ~c",
782+
"a ^ b ^ c",
783+
"~(a | b) | (a ^ b ^ c)",
784+
"~(b ^ c) & (a | b)",
785+
"~(b ^ c)",
786+
"c ^ (a & ~b)",
787+
"~((a | b) & (b ^ c))",
788+
"b ^ (a & ~c)",
789+
"~((a | c) & (b ^ c))",
790+
"(b & c) | (a ^ (b | c))",
791+
"~(a & (b ^ c))",
792+
"a & c",
793+
"~(a ^ c) & (a | ~b)",
794+
"c & (a | ~b)",
795+
"~((a & c) ^ (a | b))",
796+
"~(a ^ c) & (a | b)",
797+
"~(a ^ c)",
798+
"c ^ (b & ~a)",
799+
"~((a | b) & (a ^ c))",
800+
"c & (a | b)",
801+
"~c ^ (a | b)",
802+
"c",
803+
"c | ~(a | b)",
804+
"b ^ (a & (b ^ c))",
805+
"(b & c) | ~(a ^ c)",
806+
"(b & ~a) | c",
807+
"c | ~a",
808+
"a & (c | ~b)",
809+
"~((a & c) ^ (b | c))",
810+
"a ^ ((a ^ c) & (b ^ c))",
811+
"(a & c) | ~b",
812+
"a ^ (b & ~c)",
813+
"~((b | c) & (a ^ c))",
814+
"(a & c) | (a ^ b ^ c)",
815+
"~(b & (a ^ c))",
816+
"a ^ (b & (a ^ c))",
817+
"(a & c) | ~(b ^ c)",
818+
"(a & ~b) | c",
819+
"c | ~b",
820+
"(a & c) | (a ^ b)",
821+
"~((a ^ c) & (b ^ c))",
822+
"c | (a ^ b)",
823+
"c | ~(a & b)",
824+
"a & b",
825+
"~(a ^ b) & (a | ~c)",
826+
"~(a ^ b) & (a | c)",
827+
"~(a ^ b)",
828+
"b & (a | ~c)",
829+
"~((a & b) ^ (a | c))",
830+
"b ^ (c & ~a)",
831+
"~((a | c) & (a ^ b))",
832+
"b & (a | c)",
833+
"~b ^ (a | c)",
834+
"c ^ (a & (b ^ c))",
835+
"(b & c) | ~(a ^ b)",
836+
"b",
837+
"b | ~(a | c)",
838+
"(c & ~a) | b",
839+
"b | ~a",
840+
"a & (b | ~c)",
841+
"~((a & b) ^ (b | c))",
842+
"a ^ (c & ~b)",
843+
"~((b | c) & (a ^ b))",
844+
"a ^ ((a ^ b) & (b ^ c))",
845+
"(a & b) | ~c",
846+
"(a & b) | (a ^ b ^ c)",
847+
"~(c & (a ^ b))",
848+
"a ^ (c & (a ^ b))",
849+
"(a & b) | ~(b ^ c)",
850+
"(a & b) | (a ^ c)",
851+
"~((a ^ b) & (b ^ c))",
852+
"(a & ~c) | b",
853+
"b | ~c",
854+
"b | (a ^ c)",
855+
"b | ~(a & c)",
856+
"a & (b | c)",
857+
"~a ^ (b | c)",
858+
"c ^ (b & (a ^ c))",
859+
"(a & c) | ~(a ^ b)",
860+
"b ^ (c & (a ^ b))",
861+
"(a & b) | ~(a ^ c)",
862+
"(a & b) | (b ^ c)",
863+
"~((a ^ b) & (a ^ c))",
864+
"(a | b) & ((a & b) | c)",
865+
"(a & b) | (b ^ c ^ ~a)",
866+
"(a & b) | c",
867+
"c | ~(a ^ b)",
868+
"(a & c) | b",
869+
"b | ~(a ^ c)",
870+
"b | c",
871+
"~a | b | c",
872+
"a",
873+
"a | ~(b | c)",
874+
"a | (c & ~b)",
875+
"a | ~b",
876+
"a | (b & ~c)",
877+
"a | ~c",
878+
"a | (b ^ c)",
879+
"a | ~(b & c)",
880+
"a | (b & c)",
881+
"a | ~(b ^ c)",
882+
"a | c",
883+
"~b | a | c",
884+
"a | b",
885+
"~c | a | b",
886+
"a | b | c",
887+
"-1",
888+
};
889+
625890
static bool printPTERNLOGComments(const MCInst *MI, raw_ostream &OS,
626891
const MCInstrInfo &MCII) {
627892
unsigned NumOperands = MI->getNumOperands();
@@ -650,58 +915,35 @@ static bool printPTERNLOGComments(const MCInst *MI, raw_ostream &OS,
650915
default:
651916
return false;
652917
}
653-
const char *DestName = getRegName(MI->getOperand(0).getReg());
654-
const char *Src1Name = getRegName(MI->getOperand(1).getReg());
655-
const char *Src2Name = getRegName(MI->getOperand(Src2Idx).getReg());
656-
const char *Src3Name =
918+
StringRef DestName = getRegName(MI->getOperand(0).getReg());
919+
StringRef Src1Name = getRegName(MI->getOperand(1).getReg());
920+
StringRef Src2Name = getRegName(MI->getOperand(Src2Idx).getReg());
921+
StringRef Src3Name =
657922
Src3Idx != -1 ? getRegName(MI->getOperand(Src3Idx).getReg()) : "mem";
658923
uint8_t TruthTable = MI->getOperand(NumOperands - 1).getImm();
659924

925+
StringRef SrcNames[] = {Src1Name, Src2Name, Src3Name};
926+
660927
OS << DestName;
661928
printMasking(OS, MI, MCII);
662929
OS << " = ";
663930

664-
constexpr unsigned kNumVariables = 3;
665-
constexpr unsigned kNumTruthTableEntries = 1 << kNumVariables;
666-
int NumMinterms = llvm::popcount(TruthTable);
667-
if (NumMinterms == 0) {
668-
OS << '0';
669-
} else if (NumMinterms == kNumTruthTableEntries) {
670-
OS << "-1";
671-
} else {
672-
while (TruthTable != 0) {
673-
// Index of the lowest bit set.
674-
unsigned I = llvm::countr_zero(TruthTable);
675-
// Clear the lowest bit set.
676-
TruthTable &= TruthTable - 1;
677-
// Our index tells us which sources are and are not complemented. Note
678-
// that the indexing goes left-to-right.
679-
bool Src1 = I & 0b100;
680-
bool Src2 = I & 0b010;
681-
bool Src3 = I & 0b001;
682-
683-
// Group in parenthesis to make the output more obvious but only if there
684-
// are multiple terms.
685-
if (NumMinterms > 1)
686-
OS << '(';
687-
688-
if (!Src1)
689-
OS << '~';
690-
OS << Src1Name << " & ";
691-
if (!Src2)
692-
OS << '~';
693-
OS << Src2Name << " & ";
694-
if (!Src3)
695-
OS << '~';
696-
OS << Src3Name;
697-
698-
if (NumMinterms > 1)
699-
OS << ')';
700-
701-
// Output an OR if there is another term in the table.
702-
if (TruthTable != 0)
703-
OS << " | ";
931+
static_assert(std::size(TernlogFunctions) == 256);
932+
std::string_view BooleanFunction = TernlogFunctions[TruthTable];
933+
934+
while (!BooleanFunction.empty()) {
935+
// Print the expression up to the next symbol.
936+
size_t SymbolOffset = BooleanFunction.find_first_of("abc");
937+
OS << BooleanFunction.substr(0, SymbolOffset);
938+
if (SymbolOffset == std::string_view::npos) {
939+
// No more symbols, that means we just printed everything.
940+
break;
704941
}
942+
// Let's replace {a,b,c} with Src{1,2,3}Name.
943+
char Symbol = BooleanFunction[SymbolOffset];
944+
OS << SrcNames[Symbol - 'a'];
945+
// Consume the part of the expression we handled.
946+
BooleanFunction.remove_prefix(SymbolOffset + 1);
705947
}
706948
OS << '\n';
707949
return true;

0 commit comments

Comments
 (0)