5672 if (JSC::Options::defaultB3OptLevel() < 2)
5673 return;
5674 Vector<int32_t> amounts = { 1, 34, 63 };
5675
5676 // Test Pattern: d = n & (m >> amount)
5677 auto test = [&] (int64_t n, int64_t m, int32_t amount) -> int64_t {
5678 Procedure proc;
5679 BasicBlock* root = proc.addBlock();
5680
5681 Value* nValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
5682 Value* mValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
5683 Value* amountValue = root->appendNew<Const32Value>(proc, Origin(), amount);
5684
5685 Value* shiftValue = root->appendNew<Value>(proc, SShr, Origin(), mValue, amountValue);
5686 root->appendNewControlValue(
5687 proc, Return, Origin(),
5688 root->appendNew<Value>(proc, BitAnd, Origin(), nValue, shiftValue));
5689
5690 auto code = compileProc(proc);
5691 if (isARM64()) {
5692 std::string regex(".*and.*,.*,.*,.*asr #");
5693 regex += std::to_string(amount) + ".*";
5694 checkUsesInstruction(*code, regex.c_str(), true);
5695 }
5696 return invoke<int64_t>(*code, n, m);
5697 };
5698
5699 for (auto nOperand : int64Operands()) {
5700 for (auto mOperand : int64Operands()) {
5701 for (auto amount : amounts) {
5702 int64_t n = nOperand.value;
5703 int64_t m = mOperand.value;
5704 CHECK_EQ(test(n, m, amount), n & (m >> amount));
5705 }
5706 }
5707 }
5708}
5709
5710void testAndUnsignedRightShift64()
5711{
5712 if (JSC::Options::defaultB3OptLevel() < 2)
5713 return;
5714 Vector<uint32_t> amounts = { 1, 17, 31 };
5715
5716 // Test Pattern: d = n & (m >> amount)
5717 auto test = [&] (uint64_t n, uint64_t m, uint32_t amount) -> uint64_t {
5718 Procedure proc;
5719 BasicBlock* root = proc.addBlock();
5720
5721 Value* nValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
5722 Value* mValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
5723 Value* amountValue = root->appendNew<Const32Value>(proc, Origin(), amount);
5724
5725 Value* shiftValue = root->appendNew<Value>(proc, ZShr, Origin(), mValue, amountValue);
5726 root->appendNewControlValue(
5727 proc, Return, Origin(),
5728 root->appendNew<Value>(proc, BitAnd, Origin(), nValue, shiftValue));
5729
5730 auto code = compileProc(proc);
5731 if (isARM64()) {
5732 std::string regex(".*and.*,.*,.*,.*lsr #");
5733 regex += std::to_string(amount) + ".*";
5734 checkUsesInstruction(*code, regex.c_str(), true);
5735 }
5736 return invoke<uint64_t>(*code, n, m);
5737 };
5738
5739 for (auto nOperand : int64Operands()) {
5740 for (auto mOperand : int64Operands()) {
5741 for (auto amount : amounts) {
5742 uint64_t n = nOperand.value;
5743 uint64_t m = mOperand.value;
5744 CHECK_EQ(test(n, m, amount), n & (m >> amount));
5745 }
5746 }
5747 }
5748}
5749
5750void testXorLeftShift32()
5751{
5752 if (JSC::Options::defaultB3OptLevel() < 2)
5753 return;
5754 Vector<int32_t> amounts = { 1, 17, 31 };
5755
5756 // Test Pattern: d = n ^ (m << amount)
5757 auto test = [&] (int32_t n, int32_t m, int32_t amount) -> int32_t {
5758 Procedure proc;
5759 BasicBlock* root = proc.addBlock();
5760
5761 Value* nValue = root->appendNew<Value>(
5762 proc, Trunc, Origin(),
5763 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
5764 Value* mValue = root->appendNew<Value>(
5765 proc, Trunc, Origin(),
5766 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
5767 Value* amountValue = root->appendNew<Const32Value>(proc, Origin(), amount);
5768
5769 Value* shiftValue = root->appendNew<Value>(proc, Shl, Origin(), mValue, amountValue);
5770 root->appendNewControlValue(
5771 proc, Return, Origin(),
5772 root->appendNew<Value>(proc, BitXor, Origin(), nValue, shiftValue));
5773
5774 auto code = compileProc(proc);
5775 if (isARM64()) {
5776 std::string regex(".*eor.*,.*,.*,.*lsl #");
5777 regex += std::to_string(amount) + ".*";
5778 checkUsesInstruction(*code, regex.c_str(), true);
5779 }
5780 return invoke<int32_t>(*code, n, m);
5781 };
5782
5783 for (auto nOperand : int32Operands()) {
5784 for (auto mOperand : int32Operands()) {
5785 for (auto amount : amounts) {
5786 int32_t n = nOperand.value;
5787 int32_t m = mOperand.value;
5788 CHECK_EQ(test(n, m, amount), n ^ (m << amount));
5789 }
5790 }
5791 }
5792}
5793
5794void testXorRightShift32()
5795{
5796 if (JSC::Options::defaultB3OptLevel() < 2)
5797 return;
5798 Vector<int32_t> amounts = { 1, 17, 31 };
5799
5800 // Test Pattern: d = n ^ (m >> amount)
5801 auto test = [&] (int32_t n, int32_t m, int32_t amount) -> int32_t {
5802 Procedure proc;
5803 BasicBlock* root = proc.addBlock();
5804
5805 Value* nValue = root->appendNew<Value>(
5806 proc, Trunc, Origin(),
5807 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
5808 Value* mValue = root->appendNew<Value>(
5809 proc, Trunc, Origin(),
5810 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
5811 Value* amountValue = root->appendNew<Const32Value>(proc, Origin(), amount);
5812
5813 Value* shiftValue = root->appendNew<Value>(proc, SShr, Origin(), mValue, amountValue);
5814 root->appendNewControlValue(
5815 proc, Return, Origin(),
5816 root->appendNew<Value>(proc, BitXor, Origin(), nValue, shiftValue));
5817
5818 auto code = compileProc(proc);
5819 if (isARM64()) {
5820 std::string regex(".*eor.*,.*,.*,.*asr #");
5821 regex += std::to_string(amount) + ".*";
5822 checkUsesInstruction(*code, regex.c_str(), true);
5823 }
5824 return invoke<int32_t>(*code, n, m);
5825 };
5826
5827 for (auto nOperand : int32Operands()) {
5828 for (auto mOperand : int32Operands()) {
5829 for (auto amount : amounts) {
5830 int32_t n = nOperand.value;
5831 int32_t m = mOperand.value;
5832 CHECK_EQ(test(n, m, amount), n ^ (m >> amount));
5833 }
5834 }
5835 }
5836}
5837
5838void testXorUnsignedRightShift32()
5839{
5840 if (JSC::Options::defaultB3OptLevel() < 2)
5841 return;
5842 Vector<uint32_t> amounts = { 1, 17, 31 };
5843
5844 // Test Pattern: d = n ^ (m >> amount)
5845 auto test = [&] (uint32_t n, uint32_t m, uint32_t amount) -> uint32_t {
5846 Procedure proc;
5847 BasicBlock* root = proc.addBlock();
5848
5849 Value* nValue = root->appendNew<Value>(
5850 proc, Trunc, Origin(),
5851 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
5852 Value* mValue = root->appendNew<Value>(
5853 proc, Trunc, Origin(),
5854 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
5855 Value* amountValue = root->appendNew<Const32Value>(proc, Origin(), amount);
5856
5857 Value* shiftValue = root->appendNew<Value>(proc, ZShr, Origin(), mValue, amountValue);
5858 root->appendNewControlValue(
5859 proc, Return, Origin(),
5860 root->appendNew<Value>(proc, BitXor, Origin(), nValue, shiftValue));
5861
5862 auto code = compileProc(proc);
5863 if (isARM64()) {
5864 std::string regex(".*eor.*,.*,.*,.*lsr #");
5865 regex += std::to_string(amount) + ".*";
5866 checkUsesInstruction(*code, regex.c_str(), true);
5867 }
5868 return invoke<uint32_t>(*code, n, m);
5869 };
5870
5871 for (auto nOperand : int32Operands()) {
5872 for (auto mOperand : int32Operands()) {
5873 for (auto amount : amounts) {
5874 uint32_t n = nOperand.value;
5875 uint32_t m = mOperand.value;
5876 CHECK_EQ(test(n, m, amount), n ^ (m >> amount));
5877 }
5878 }
5879 }
5880}
5881
5882void testXorLeftShift64()
5883{
5884 if (JSC::Options::defaultB3OptLevel() < 2)
5885 return;
5886 Vector<int32_t> amounts = { 1, 34, 63 };
5887
5888 // Test Pattern: d = n ^ (m << amount)
5889 auto test = [&] (int64_t n, int64_t m, int32_t amount) -> int64_t {
5890 Procedure proc;
5891 BasicBlock* root = proc.addBlock();
5892
5893 Value* nValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
5894 Value* mValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
5895 Value* amountValue = root->appendNew<Const32Value>(proc, Origin(), amount);
5896
5897 Value* shiftValue = root->appendNew<Value>(proc, Shl, Origin(), mValue, amountValue);
5898 root->appendNewControlValue(
5899 proc, Return, Origin(),
5900 root->appendNew<Value>(proc, BitXor, Origin(), nValue, shiftValue));
5901
5902 auto code = compileProc(proc);
5903 if (isARM64()) {
5904 std::string regex(".*eor.*,.*,.*,.*lsl #");
5905 regex += std::to_string(amount) + ".*";
5906 checkUsesInstruction(*code, regex.c_str(), true);
5907 }
5908 return invoke<int64_t>(*code, n, m);
5909 };
5910
5911 for (auto nOperand : int64Operands()) {
5912 for (auto mOperand : int64Operands()) {
5913 for (auto amount : amounts) {
5914 int64_t n = nOperand.value;
5915 int64_t m = mOperand.value;
5916 CHECK_EQ(test(n, m, amount), n ^ (m << amount));
5917 }
5918 }
5919 }
5920}
5921
5922void testXorRightShift64()
5923{
5924 if (JSC::Options::defaultB3OptLevel() < 2)
5925 return;
5926 Vector<int32_t> amounts = { 1, 34, 63 };
5927
5928 // Test Pattern: d = n ^ (m >> amount)
5929 auto test = [&] (int64_t n, int64_t m, int32_t amount) -> int64_t {
5930 Procedure proc;
5931 BasicBlock* root = proc.addBlock();
5932
5933 Value* nValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
5934 Value* mValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
5935 Value* amountValue = root->appendNew<Const32Value>(proc, Origin(), amount);
5936
5937 Value* shiftValue = root->appendNew<Value>(proc, SShr, Origin(), mValue, amountValue);
5938 root->appendNewControlValue(
5939 proc, Return, Origin(),
5940 root->appendNew<Value>(proc, BitXor, Origin(), nValue, shiftValue));
5941
5942 auto code = compileProc(proc);
5943 if (isARM64()) {
5944 std::string regex(".*eor.*,.*,.*,.*asr #");
5945 regex += std::to_string(amount) + ".*";
5946 checkUsesInstruction(*code, regex.c_str(), true);
5947 }
5948 return invoke<int64_t>(*code, n, m);
5949 };
5950
5951 for (auto nOperand : int64Operands()) {
5952 for (auto mOperand : int64Operands()) {
5953 for (auto amount : amounts) {
5954 int64_t n = nOperand.value;
5955 int64_t m = mOperand.value;
5956 CHECK_EQ(test(n, m, amount), n ^ (m >> amount));
5957 }
5958 }
5959 }
5960}
5961
5962void testXorUnsignedRightShift64()
5963{
5964 if (JSC::Options::defaultB3OptLevel() < 2)
5965 return;
5966 Vector<uint32_t> amounts = { 1, 17, 31 };
5967
5968 // Test Pattern: d = n ^ (m >> amount)
5969 auto test = [&] (uint64_t n, uint64_t m, uint32_t amount) -> uint64_t {
5970 Procedure proc;
5971 BasicBlock* root = proc.addBlock();
5972
5973 Value* nValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
5974 Value* mValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
5975 Value* amountValue = root->appendNew<Const32Value>(proc, Origin(), amount);
5976
5977 Value* shiftValue = root->appendNew<Value>(proc, ZShr, Origin(), mValue, amountValue);
5978 root->appendNewControlValue(
5979 proc, Return, Origin(),
5980 root->appendNew<Value>(proc, BitXor, Origin(), nValue, shiftValue));
5981
5982 auto code = compileProc(proc);
5983 if (isARM64()) {
5984 std::string regex(".*eor.*,.*,.*,.*lsr #");
5985 regex += std::to_string(amount) + ".*";
5986 checkUsesInstruction(*code, regex.c_str(), true);
5987 }
5988 return invoke<uint64_t>(*code, n, m);
5989 };
5990
5991 for (auto nOperand : int64Operands()) {
5992 for (auto mOperand : int64Operands()) {
5993 for (auto amount : amounts) {
5994 uint64_t n = nOperand.value;
5995 uint64_t m = mOperand.value;
5996 CHECK_EQ(test(n, m, amount), n ^ (m >> amount));
5997 }
5998 }
5999 }
6000}
6001
6002void testOrLeftShift32()
6003{
6004 if (JSC::Options::defaultB3OptLevel() < 2)
6005 return;
6006 Vector<int32_t> amounts = { 1, 17, 31 };
6007
6008 // Test Pattern: d = n | (m << amount)
6009 auto test = [&] (int32_t n, int32_t m, int32_t amount) -> int32_t {
6010 Procedure proc;
6011 BasicBlock* root = proc.addBlock();
6012
6013 Value* nValue = root->appendNew<Value>(
6014 proc, Trunc, Origin(),
6015 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
6016 Value* mValue = root->appendNew<Value>(
6017 proc, Trunc, Origin(),
6018 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
6019 Value* amountValue = root->appendNew<Const32Value>(proc, Origin(), amount);
6020
6021 Value* shiftValue = root->appendNew<Value>(proc, Shl, Origin(), mValue, amountValue);
6022 root->appendNewControlValue(
6023 proc, Return, Origin(),
6024 root->appendNew<Value>(proc, BitOr, Origin(), nValue, shiftValue));
6025
6026 auto code = compileProc(proc);
6027 if (isARM64()) {
6028 std::string regex(".*orr.*,.*,.*,.*lsl #");
6029 regex += std::to_string(amount) + ".*";
6030 checkUsesInstruction(*code, regex.c_str(), true);
6031 }
6032 return invoke<int32_t>(*code, n, m);
6033 };
6034
6035 for (auto nOperand : int32Operands()) {
6036 for (auto mOperand : int32Operands()) {
6037 for (auto amount : amounts) {
6038 int32_t n = nOperand.value;
6039 int32_t m = mOperand.value;
6040 CHECK_EQ(test(n, m, amount), n | (m << amount));
6041 }
6042 }
6043 }
6044}
6045
6046void testOrRightShift32()
6047{
6048 if (JSC::Options::defaultB3OptLevel() < 2)
6049 return;
6050 Vector<int32_t> amounts = { 1, 17, 31 };
6051
6052 // Test Pattern: d = n | (m >> amount)
6053 auto test = [&] (int32_t n, int32_t m, int32_t amount) -> int32_t {
6054 Procedure proc;
6055 BasicBlock* root = proc.addBlock();
6056
6057 Value* nValue = root->appendNew<Value>(
6058 proc, Trunc, Origin(),
6059 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
6060 Value* mValue = root->appendNew<Value>(
6061 proc, Trunc, Origin(),
6062 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
6063 Value* amountValue = root->appendNew<Const32Value>(proc, Origin(), amount);
6064
6065 Value* shiftValue = root->appendNew<Value>(proc, SShr, Origin(), mValue, amountValue);
6066 root->appendNewControlValue(
6067 proc, Return, Origin(),
6068 root->appendNew<Value>(proc, BitOr, Origin(), nValue, shiftValue));
6069
6070 auto code = compileProc(proc);
6071 if (isARM64()) {
6072 std::string regex(".*orr.*,.*,.*,.*asr #");
6073 regex += std::to_string(amount) + ".*";
6074 checkUsesInstruction(*code, regex.c_str(), true);
6075 }
6076 return invoke<int32_t>(*code, n, m);
6077 };
6078
6079 for (auto nOperand : int32Operands()) {
6080 for (auto mOperand : int32Operands()) {
6081 for (auto amount : amounts) {
6082 int32_t n = nOperand.value;
6083 int32_t m = mOperand.value;
6084 CHECK_EQ(test(n, m, amount), n | (m >> amount));
6085 }
6086 }
6087 }
6088}
6089
6090void testOrUnsignedRightShift32()
6091{
6092 if (JSC::Options::defaultB3OptLevel() < 2)
6093 return;
6094 Vector<uint32_t> amounts = { 1, 17, 31 };
6095
6096 // Test Pattern: d = n | (m >> amount)
6097 auto test = [&] (uint32_t n, uint32_t m, uint32_t amount) -> uint32_t {
6098 Procedure proc;
6099 BasicBlock* root = proc.addBlock();
6100
6101 Value* nValue = root->appendNew<Value>(
6102 proc, Trunc, Origin(),
6103 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
6104 Value* mValue = root->appendNew<Value>(
6105 proc, Trunc, Origin(),
6106 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
6107 Value* amountValue = root->appendNew<Const32Value>(proc, Origin(), amount);
6108
6109 Value* shiftValue = root->appendNew<Value>(proc, ZShr, Origin(), mValue, amountValue);
6110 root->appendNewControlValue(
6111 proc, Return, Origin(),
6112 root->appendNew<Value>(proc, BitOr, Origin(), nValue, shiftValue));
6113
6114 auto code = compileProc(proc);
6115 if (isARM64()) {
6116 std::string regex(".*orr.*,.*,.*,.*lsr #");
6117 regex += std::to_string(amount) + ".*";
6118 checkUsesInstruction(*code, regex.c_str(), true);
6119 }
6120 return invoke<uint32_t>(*code, n, m);
6121 };
6122
6123 for (auto nOperand : int32Operands()) {
6124 for (auto mOperand : int32Operands()) {
6125 for (auto amount : amounts) {
6126 uint32_t n = nOperand.value;
6127 uint32_t m = mOperand.value;
6128 CHECK_EQ(test(n, m, amount), n | (m >> amount));
6129 }
6130 }
6131 }
6132}
6133
6134void testOrLeftShift64()
6135{
6136 if (JSC::Options::defaultB3OptLevel() < 2)
6137 return;
6138 Vector<int32_t> amounts = { 1, 34, 63 };
6139
6140 // Test Pattern: d = n | (m << amount)
6141 auto test = [&] (int64_t n, int64_t m, int32_t amount) -> int64_t {
6142 Procedure proc;
6143 BasicBlock* root = proc.addBlock();
6144
6145 Value* nValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
6146 Value* mValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
6147 Value* amountValue = root->appendNew<Const32Value>(proc, Origin(), amount);
6148
6149 Value* shiftValue = root->appendNew<Value>(proc, Shl, Origin(), mValue, amountValue);
6150 root->appendNewControlValue(
6151 proc, Return, Origin(),
6152 root->appendNew<Value>(proc, BitOr, Origin(), nValue, shiftValue));
6153
6154 auto code = compileProc(proc);
6155 if (isARM64()) {
6156 std::string regex(".*orr.*,.*,.*,.*lsl #");
6157 regex += std::to_string(amount) + ".*";
6158 checkUsesInstruction(*code, regex.c_str(), true);
6159 }
6160 return invoke<int64_t>(*code, n, m);
6161 };
6162
6163 for (auto nOperand : int64Operands()) {
6164 for (auto mOperand : int64Operands()) {
6165 for (auto amount : amounts) {
6166 int64_t n = nOperand.value;
6167 int64_t m = mOperand.value;
6168 CHECK_EQ(test(n, m, amount), n | (m << amount));
6169 }
6170 }
6171 }
6172}
6173
6174void testOrRightShift64()
6175{
6176 if (JSC::Options::defaultB3OptLevel() < 2)
6177 return;
6178 Vector<int32_t> amounts = { 1, 34, 63 };
6179
6180 // Test Pattern: d = n | (m >> amount)
6181 auto test = [&] (int64_t n, int64_t m, int32_t amount) -> int64_t {
6182 Procedure proc;
6183 BasicBlock* root = proc.addBlock();
6184
6185 Value* nValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
6186 Value* mValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
6187 Value* amountValue = root->appendNew<Const32Value>(proc, Origin(), amount);
6188
6189 Value* shiftValue = root->appendNew<Value>(proc, SShr, Origin(), mValue, amountValue);
6190 root->appendNewControlValue(
6191 proc, Return, Origin(),
6192 root->appendNew<Value>(proc, BitOr, Origin(), nValue, shiftValue));
6193
6194 auto code = compileProc(proc);
6195 if (isARM64()) {
6196 std::string regex(".*orr.*,.*,.*,.*asr #");
6197 regex += std::to_string(amount) + ".*";
6198 checkUsesInstruction(*code, regex.c_str(), true);
6199 }
6200 return invoke<int64_t>(*code, n, m);
6201 };
6202
6203 for (auto nOperand : int64Operands()) {
6204 for (auto mOperand : int64Operands()) {
6205 for (auto amount : amounts) {
6206 int64_t n = nOperand.value;
6207 int64_t m = mOperand.value;
6208 CHECK_EQ(test(n, m, amount), n | (m >> amount));
6209 }
6210 }
6211 }
6212}
6213
6214void testOrUnsignedRightShift64()
6215{
6216 if (JSC::Options::defaultB3OptLevel() < 2)
6217 return;
6218 Vector<uint32_t> amounts = { 1, 17, 31 };
6219
6220 // Test Pattern: d = n | (m >> amount)
6221 auto test = [&] (uint64_t n, uint64_t m, uint32_t amount) -> uint64_t {
6222 Procedure proc;
6223 BasicBlock* root = proc.addBlock();
6224
6225 Value* nValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
6226 Value* mValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
6227 Value* amountValue = root->appendNew<Const32Value>(proc, Origin(), amount);
6228
6229 Value* shiftValue = root->appendNew<Value>(proc, ZShr, Origin(), mValue, amountValue);
6230 root->appendNewControlValue(
6231 proc, Return, Origin(),
6232 root->appendNew<Value>(proc, BitOr, Origin(), nValue, shiftValue));
6233
6234 auto code = compileProc(proc);
6235 if (isARM64()) {
6236 std::string regex(".*orr.*,.*,.*,.*lsr #");
6237 regex += std::to_string(amount) + ".*";
6238 checkUsesInstruction(*code, regex.c_str(), true);
6239 }
6240 return invoke<uint64_t>(*code, n, m);
6241 };
6242
6243 for (auto nOperand : int64Operands()) {
6244 for (auto mOperand : int64Operands()) {
6245 for (auto amount : amounts) {
6246 uint64_t n = nOperand.value;
6247 uint64_t m = mOperand.value;
6248 CHECK_EQ(test(n, m, amount), n | (m >> amount));
6249 }
6250 }
6251 }
6252}
6253
6254void testBitAndZeroShiftRightArgImmMask32()
6255{
6256 // Turn this: (tmp >> imm) & mask
6257 // Into this: tmp >> imm
6258 uint32_t tmp = 0xffffffff;
6259 Vector<uint32_t> imms = { 4, 28, 31 };
6260 Vector<uint32_t> masks = { 0x0fffffff, 0xf, 0xffff };
6261
6262 auto test = [&] (uint32_t imm, uint32_t mask) {
6263 Procedure proc;
6264 BasicBlock* root = proc.addBlock();
6265
6266 Value* tmpValue = root->appendNew<Value>(
6267 proc, Trunc, Origin(),
6268 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
6269 Value* immValue = root->appendNew<Const32Value>(proc, Origin(), imm);
6270 Value* leftValue = root->appendNew<Value>(proc, ZShr, Origin(), tmpValue, immValue);
6271 Value* rightValue = root->appendNew<Const32Value>(proc, Origin(), mask);
6272 root->appendNewControlValue(
6273 proc, Return, Origin(),
6274 root->appendNew<Value>(proc, BitAnd, Origin(), leftValue, rightValue));
6275
6276 auto code = compileProc(proc);
6277 if (isARM64())
6278 checkUsesInstruction(*code, "lsr");
6279 uint32_t lhs = invoke<uint32_t>(*code, tmp);
6280 uint32_t rhs = tmp >> imm;
6281 CHECK(lhs == rhs);
6282 };
6283
6284 for (size_t i = 0; i < imms.size(); ++i)
6285 test(imms.at(i), masks.at(i));
6286}
6287
6288void testBitAndZeroShiftRightArgImmMask64()
6289{
6290 // Turn this: (tmp >> imm) & mask
6291 // Into this: tmp >> imm
6292 uint64_t tmp = 0xffffffffffffffff;
6293 Vector<uint64_t> imms = { 4, 60, 63 };
6294 Vector<uint64_t> masks = { 0x0fffffffffffffff, 0xf, 0xffff };
6295
6296 auto test = [&] (uint64_t imm, uint64_t mask) {
6297 Procedure proc;
6298 BasicBlock* root = proc.addBlock();
6299
6300 Value* tmpValue = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
6301 Value* immValue = root->appendNew<Const32Value>(proc, Origin(), imm);
6302 Value* leftValue = root->appendNew<Value>(proc, ZShr, Origin(), tmpValue, immValue);
6303 Value* rightValue = root->appendNew<Const64Value>(proc, Origin(), mask);
6304 root->appendNewControlValue(
6305 proc, Return, Origin(),
6306 root->appendNew<Value>(proc, BitAnd, Origin(), leftValue, rightValue));
6307
6308 auto code = compileProc(proc);
6309 if (isARM64())
6310 checkUsesInstruction(*code, "lsr");
6311 uint64_t lhs = invoke<uint64_t>(*code, tmp);
6312 uint64_t rhs = tmp >> imm;
6313 CHECK(lhs == rhs);
6314 };
6315
6316 for (size_t i = 0; i < imms.size(); ++i)
6317 test(imms.at(i), masks.at(i));
6318}
6319
6320static void testBitAndArgs(int64_t a, int64_t b)
6321{
6322 Procedure proc;
6323 BasicBlock* root = proc.addBlock();
6324 root->appendNewControlValue(
6325 proc, Return, Origin(),
6326 root->appendNew<Value>(
6327 proc, BitAnd, Origin(),
6328 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
6329 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
6330
6331 CHECK(compileAndRun<int64_t>(proc, a, b) == (a & b));
6332}
6333
6334static void testBitAndSameArg(int64_t a)
6335{
6336 Procedure proc;
6337 BasicBlock* root = proc.addBlock();
6338 Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
6339 root->appendNewControlValue(
6340 proc, Return, Origin(),
6341 root->appendNew<Value>(
6342 proc, BitAnd, Origin(),
6343 argument,
6344 argument));
6345
6346 CHECK(compileAndRun<int64_t>(proc, a) == a);
6347}
6348
6349static void testBitAndNotNot(int64_t a, int64_t b)
6350{
6351 Procedure proc;
6352 BasicBlock* root = proc.addBlock();
6353 Value* argA = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
6354 Value* argB = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
6355 Value* notA = root->appendNew<Value>(proc, BitXor, Origin(), argA, root->appendNew<Const64Value>(proc, Origin(), -1));
6356 Value* notB = root->appendNew<Value>(proc, BitXor, Origin(), argB, root->appendNew<Const64Value>(proc, Origin(), -1));
6357 root->appendNewControlValue(
6358 proc, Return, Origin(),
6359 root->appendNew<Value>(
6360 proc, BitAnd, Origin(),
6361 notA,
6362 notB));
6363
6364 CHECK_EQ(compileAndRun<int64_t>(proc, a, b), (~a & ~b));
6365}
6366
6367static void testBitAndNotNot32(int32_t a, int32_t b)
6368{
6369 Procedure proc;
6370 BasicBlock* root = proc.addBlock();
6371 Value* argA = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
6372 Value* argB = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
6373 Value* notA = root->appendNew<Value>(proc, BitXor, Origin(), argA, root->appendNew<Const32Value>(proc, Origin(), -1));
6374 Value* notB = root->appendNew<Value>(proc, BitXor, Origin(), argB, root->appendNew<Const32Value>(proc, Origin(), -1));
6375 root->appendNewControlValue(
6376 proc, Return, Origin(),
6377 root->appendNew<Value>(
6378 proc, BitAnd, Origin(),
6379 notA,
6380 notB));
6381
6382 CHECK_EQ(compileAndRun<int32_t>(proc, a, b), (~a & ~b));
6383}
6384
6385static void testBitAndNotImm(int64_t a, int64_t b)
6386{
6387 Procedure proc;
6388 BasicBlock* root = proc.addBlock();
6389 Value* argA = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
6390 Value* notA = root->appendNew<Value>(proc, BitXor, Origin(), argA, root->appendNew<Const64Value>(proc, Origin(), -1));
6391 Value* cstB = root->appendNew<Const64Value>(proc, Origin(), b);
6392 root->appendNewControlValue(
6393 proc, Return, Origin(),
6394 root->appendNew<Value>(
6395 proc, BitAnd, Origin(),
6396 notA,
6397 cstB));
6398
6399 CHECK_EQ(compileAndRun<int64_t>(proc, a), (~a & b));
6400}
6401
6402static void testBitAndNotImm32(int32_t a, int32_t b)
6403{
6404 Procedure proc;
6405 BasicBlock* root = proc.addBlock();
6406 Value* argA = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
6407 Value* notA = root->appendNew<Value>(proc, BitXor, Origin(), argA, root->appendNew<Const32Value>(proc, Origin(), -1));
6408 Value* cstB = root->appendNew<Const32Value>(proc, Origin(), b);
6409 root->appendNewControlValue(
6410 proc, Return, Origin(),
6411 root->appendNew<Value>(
6412 proc, BitAnd, Origin(),