10b57cec5SDimitry Andric //===-- AutoUpgrade.cpp - Implement auto-upgrade helper functions ---------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file implements the auto-upgrade helper functions. 100b57cec5SDimitry Andric // This is where deprecated IR intrinsics and other IR features are updated to 110b57cec5SDimitry Andric // current specifications. 120b57cec5SDimitry Andric // 130b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 140b57cec5SDimitry Andric 150b57cec5SDimitry Andric #include "llvm/IR/AutoUpgrade.h" 1606c3fb27SDimitry Andric #include "llvm/ADT/StringRef.h" 170b57cec5SDimitry Andric #include "llvm/ADT/StringSwitch.h" 1806c3fb27SDimitry Andric #include "llvm/BinaryFormat/Dwarf.h" 1906c3fb27SDimitry Andric #include "llvm/IR/AttributeMask.h" 200b57cec5SDimitry Andric #include "llvm/IR/Constants.h" 210b57cec5SDimitry Andric #include "llvm/IR/DebugInfo.h" 2206c3fb27SDimitry Andric #include "llvm/IR/DebugInfoMetadata.h" 230b57cec5SDimitry Andric #include "llvm/IR/DiagnosticInfo.h" 240b57cec5SDimitry Andric #include "llvm/IR/Function.h" 250b57cec5SDimitry Andric #include "llvm/IR/IRBuilder.h" 265ffd83dbSDimitry Andric #include "llvm/IR/InstVisitor.h" 27fe6060f1SDimitry Andric #include "llvm/IR/Instruction.h" 280b57cec5SDimitry Andric #include "llvm/IR/IntrinsicInst.h" 29e8d8bef9SDimitry Andric #include "llvm/IR/Intrinsics.h" 30480093f4SDimitry Andric #include "llvm/IR/IntrinsicsAArch64.h" 31480093f4SDimitry Andric #include "llvm/IR/IntrinsicsARM.h" 3206c3fb27SDimitry Andric #include "llvm/IR/IntrinsicsNVPTX.h" 3306c3fb27SDimitry Andric #include "llvm/IR/IntrinsicsRISCV.h" 341ac55f4cSDimitry Andric #include "llvm/IR/IntrinsicsWebAssembly.h" 35480093f4SDimitry Andric #include "llvm/IR/IntrinsicsX86.h" 360b57cec5SDimitry Andric #include "llvm/IR/LLVMContext.h" 3706c3fb27SDimitry Andric #include "llvm/IR/Metadata.h" 380b57cec5SDimitry Andric #include "llvm/IR/Module.h" 390b57cec5SDimitry Andric #include "llvm/IR/Verifier.h" 4006c3fb27SDimitry Andric #include "llvm/Support/CommandLine.h" 410b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 420b57cec5SDimitry Andric #include "llvm/Support/Regex.h" 4306c3fb27SDimitry Andric #include "llvm/TargetParser/Triple.h" 440b57cec5SDimitry Andric #include <cstring> 4506c3fb27SDimitry Andric 460b57cec5SDimitry Andric using namespace llvm; 470b57cec5SDimitry Andric 4806c3fb27SDimitry Andric static cl::opt<bool> 4906c3fb27SDimitry Andric DisableAutoUpgradeDebugInfo("disable-auto-upgrade-debug-info", 5006c3fb27SDimitry Andric cl::desc("Disable autoupgrade of debug info")); 5106c3fb27SDimitry Andric 520b57cec5SDimitry Andric static void rename(GlobalValue *GV) { GV->setName(GV->getName() + ".old"); } 530b57cec5SDimitry Andric 540b57cec5SDimitry Andric // Upgrade the declarations of the SSE4.1 ptest intrinsics whose arguments have 550b57cec5SDimitry Andric // changed their type from v4f32 to v2i64. 567a6dacacSDimitry Andric static bool upgradePTESTIntrinsic(Function *F, Intrinsic::ID IID, 570b57cec5SDimitry Andric Function *&NewFn) { 580b57cec5SDimitry Andric // Check whether this is an old version of the function, which received 590b57cec5SDimitry Andric // v4f32 arguments. 600b57cec5SDimitry Andric Type *Arg0Type = F->getFunctionType()->getParamType(0); 615ffd83dbSDimitry Andric if (Arg0Type != FixedVectorType::get(Type::getFloatTy(F->getContext()), 4)) 620b57cec5SDimitry Andric return false; 630b57cec5SDimitry Andric 640b57cec5SDimitry Andric // Yes, it's old, replace it with new version. 650b57cec5SDimitry Andric rename(F); 660b57cec5SDimitry Andric NewFn = Intrinsic::getDeclaration(F->getParent(), IID); 670b57cec5SDimitry Andric return true; 680b57cec5SDimitry Andric } 690b57cec5SDimitry Andric 700b57cec5SDimitry Andric // Upgrade the declarations of intrinsic functions whose 8-bit immediate mask 710b57cec5SDimitry Andric // arguments have changed their type from i32 to i8. 727a6dacacSDimitry Andric static bool upgradeX86IntrinsicsWith8BitMask(Function *F, Intrinsic::ID IID, 730b57cec5SDimitry Andric Function *&NewFn) { 740b57cec5SDimitry Andric // Check that the last argument is an i32. 750b57cec5SDimitry Andric Type *LastArgType = F->getFunctionType()->getParamType( 760b57cec5SDimitry Andric F->getFunctionType()->getNumParams() - 1); 770b57cec5SDimitry Andric if (!LastArgType->isIntegerTy(32)) 780b57cec5SDimitry Andric return false; 790b57cec5SDimitry Andric 800b57cec5SDimitry Andric // Move this function aside and map down. 810b57cec5SDimitry Andric rename(F); 820b57cec5SDimitry Andric NewFn = Intrinsic::getDeclaration(F->getParent(), IID); 830b57cec5SDimitry Andric return true; 840b57cec5SDimitry Andric } 850b57cec5SDimitry Andric 86e8d8bef9SDimitry Andric // Upgrade the declaration of fp compare intrinsics that change return type 87e8d8bef9SDimitry Andric // from scalar to vXi1 mask. 887a6dacacSDimitry Andric static bool upgradeX86MaskedFPCompare(Function *F, Intrinsic::ID IID, 89e8d8bef9SDimitry Andric Function *&NewFn) { 90e8d8bef9SDimitry Andric // Check if the return type is a vector. 91e8d8bef9SDimitry Andric if (F->getReturnType()->isVectorTy()) 92e8d8bef9SDimitry Andric return false; 93e8d8bef9SDimitry Andric 94e8d8bef9SDimitry Andric rename(F); 95e8d8bef9SDimitry Andric NewFn = Intrinsic::getDeclaration(F->getParent(), IID); 96e8d8bef9SDimitry Andric return true; 97e8d8bef9SDimitry Andric } 98e8d8bef9SDimitry Andric 997a6dacacSDimitry Andric static bool upgradeX86BF16Intrinsic(Function *F, Intrinsic::ID IID, 100bdd1243dSDimitry Andric Function *&NewFn) { 101bdd1243dSDimitry Andric if (F->getReturnType()->getScalarType()->isBFloatTy()) 102bdd1243dSDimitry Andric return false; 103bdd1243dSDimitry Andric 104bdd1243dSDimitry Andric rename(F); 105bdd1243dSDimitry Andric NewFn = Intrinsic::getDeclaration(F->getParent(), IID); 106bdd1243dSDimitry Andric return true; 107bdd1243dSDimitry Andric } 108bdd1243dSDimitry Andric 1097a6dacacSDimitry Andric static bool upgradeX86BF16DPIntrinsic(Function *F, Intrinsic::ID IID, 110bdd1243dSDimitry Andric Function *&NewFn) { 111bdd1243dSDimitry Andric if (F->getFunctionType()->getParamType(1)->getScalarType()->isBFloatTy()) 112bdd1243dSDimitry Andric return false; 113bdd1243dSDimitry Andric 114bdd1243dSDimitry Andric rename(F); 115bdd1243dSDimitry Andric NewFn = Intrinsic::getDeclaration(F->getParent(), IID); 116bdd1243dSDimitry Andric return true; 117bdd1243dSDimitry Andric } 118bdd1243dSDimitry Andric 1197a6dacacSDimitry Andric static bool shouldUpgradeX86Intrinsic(Function *F, StringRef Name) { 1200b57cec5SDimitry Andric // All of the intrinsics matches below should be marked with which llvm 1210b57cec5SDimitry Andric // version started autoupgrading them. At some point in the future we would 1220b57cec5SDimitry Andric // like to use this information to remove upgrade code for some older 1230b57cec5SDimitry Andric // intrinsics. It is currently undecided how we will determine that future 1240b57cec5SDimitry Andric // point. 1255f757f3fSDimitry Andric if (Name.consume_front("avx.")) 1265f757f3fSDimitry Andric return (Name.starts_with("blend.p") || // Added in 3.7 1275f757f3fSDimitry Andric Name == "cvt.ps2.pd.256" || // Added in 3.9 1285f757f3fSDimitry Andric Name == "cvtdq2.pd.256" || // Added in 3.9 1295f757f3fSDimitry Andric Name == "cvtdq2.ps.256" || // Added in 7.0 1305f757f3fSDimitry Andric Name.starts_with("movnt.") || // Added in 3.2 1315f757f3fSDimitry Andric Name.starts_with("sqrt.p") || // Added in 7.0 1325f757f3fSDimitry Andric Name.starts_with("storeu.") || // Added in 3.9 1335f757f3fSDimitry Andric Name.starts_with("vbroadcast.s") || // Added in 3.5 1345f757f3fSDimitry Andric Name.starts_with("vbroadcastf128") || // Added in 4.0 1355f757f3fSDimitry Andric Name.starts_with("vextractf128.") || // Added in 3.7 1365f757f3fSDimitry Andric Name.starts_with("vinsertf128.") || // Added in 3.7 1375f757f3fSDimitry Andric Name.starts_with("vperm2f128.") || // Added in 6.0 1385f757f3fSDimitry Andric Name.starts_with("vpermil.")); // Added in 3.1 1395f757f3fSDimitry Andric 1405f757f3fSDimitry Andric if (Name.consume_front("avx2.")) 1415f757f3fSDimitry Andric return (Name == "movntdqa" || // Added in 5.0 1425f757f3fSDimitry Andric Name.starts_with("pabs.") || // Added in 6.0 1435f757f3fSDimitry Andric Name.starts_with("padds.") || // Added in 8.0 1445f757f3fSDimitry Andric Name.starts_with("paddus.") || // Added in 8.0 1455f757f3fSDimitry Andric Name.starts_with("pblendd.") || // Added in 3.7 1465f757f3fSDimitry Andric Name == "pblendw" || // Added in 3.7 1475f757f3fSDimitry Andric Name.starts_with("pbroadcast") || // Added in 3.8 1485f757f3fSDimitry Andric Name.starts_with("pcmpeq.") || // Added in 3.1 1495f757f3fSDimitry Andric Name.starts_with("pcmpgt.") || // Added in 3.1 1505f757f3fSDimitry Andric Name.starts_with("pmax") || // Added in 3.9 1515f757f3fSDimitry Andric Name.starts_with("pmin") || // Added in 3.9 1525f757f3fSDimitry Andric Name.starts_with("pmovsx") || // Added in 3.9 1535f757f3fSDimitry Andric Name.starts_with("pmovzx") || // Added in 3.9 1545f757f3fSDimitry Andric Name == "pmul.dq" || // Added in 7.0 1555f757f3fSDimitry Andric Name == "pmulu.dq" || // Added in 7.0 1565f757f3fSDimitry Andric Name.starts_with("psll.dq") || // Added in 3.7 1575f757f3fSDimitry Andric Name.starts_with("psrl.dq") || // Added in 3.7 1585f757f3fSDimitry Andric Name.starts_with("psubs.") || // Added in 8.0 1595f757f3fSDimitry Andric Name.starts_with("psubus.") || // Added in 8.0 1605f757f3fSDimitry Andric Name.starts_with("vbroadcast") || // Added in 3.8 1615f757f3fSDimitry Andric Name == "vbroadcasti128" || // Added in 3.7 1625f757f3fSDimitry Andric Name == "vextracti128" || // Added in 3.7 1635f757f3fSDimitry Andric Name == "vinserti128" || // Added in 3.7 1645f757f3fSDimitry Andric Name == "vperm2i128"); // Added in 6.0 1655f757f3fSDimitry Andric 1665f757f3fSDimitry Andric if (Name.consume_front("avx512.")) { 1675f757f3fSDimitry Andric if (Name.consume_front("mask.")) 1685f757f3fSDimitry Andric // 'avx512.mask.*' 1695f757f3fSDimitry Andric return (Name.starts_with("add.p") || // Added in 7.0. 128/256 in 4.0 1705f757f3fSDimitry Andric Name.starts_with("and.") || // Added in 3.9 1715f757f3fSDimitry Andric Name.starts_with("andn.") || // Added in 3.9 1725f757f3fSDimitry Andric Name.starts_with("broadcast.s") || // Added in 3.9 1735f757f3fSDimitry Andric Name.starts_with("broadcastf32x4.") || // Added in 6.0 1745f757f3fSDimitry Andric Name.starts_with("broadcastf32x8.") || // Added in 6.0 1755f757f3fSDimitry Andric Name.starts_with("broadcastf64x2.") || // Added in 6.0 1765f757f3fSDimitry Andric Name.starts_with("broadcastf64x4.") || // Added in 6.0 1775f757f3fSDimitry Andric Name.starts_with("broadcasti32x4.") || // Added in 6.0 1785f757f3fSDimitry Andric Name.starts_with("broadcasti32x8.") || // Added in 6.0 1795f757f3fSDimitry Andric Name.starts_with("broadcasti64x2.") || // Added in 6.0 1805f757f3fSDimitry Andric Name.starts_with("broadcasti64x4.") || // Added in 6.0 1815f757f3fSDimitry Andric Name.starts_with("cmp.b") || // Added in 5.0 1825f757f3fSDimitry Andric Name.starts_with("cmp.d") || // Added in 5.0 1835f757f3fSDimitry Andric Name.starts_with("cmp.q") || // Added in 5.0 1845f757f3fSDimitry Andric Name.starts_with("cmp.w") || // Added in 5.0 1855f757f3fSDimitry Andric Name.starts_with("compress.b") || // Added in 9.0 1865f757f3fSDimitry Andric Name.starts_with("compress.d") || // Added in 9.0 1875f757f3fSDimitry Andric Name.starts_with("compress.p") || // Added in 9.0 1885f757f3fSDimitry Andric Name.starts_with("compress.q") || // Added in 9.0 1895f757f3fSDimitry Andric Name.starts_with("compress.store.") || // Added in 7.0 1905f757f3fSDimitry Andric Name.starts_with("compress.w") || // Added in 9.0 1915f757f3fSDimitry Andric Name.starts_with("conflict.") || // Added in 9.0 1925f757f3fSDimitry Andric Name.starts_with("cvtdq2pd.") || // Added in 4.0 1935f757f3fSDimitry Andric Name.starts_with("cvtdq2ps.") || // Added in 7.0 updated 9.0 1945f757f3fSDimitry Andric Name == "cvtpd2dq.256" || // Added in 7.0 1955f757f3fSDimitry Andric Name == "cvtpd2ps.256" || // Added in 7.0 1965f757f3fSDimitry Andric Name == "cvtps2pd.128" || // Added in 7.0 1975f757f3fSDimitry Andric Name == "cvtps2pd.256" || // Added in 7.0 1985f757f3fSDimitry Andric Name.starts_with("cvtqq2pd.") || // Added in 7.0 updated 9.0 1995f757f3fSDimitry Andric Name == "cvtqq2ps.256" || // Added in 9.0 2005f757f3fSDimitry Andric Name == "cvtqq2ps.512" || // Added in 9.0 2015f757f3fSDimitry Andric Name == "cvttpd2dq.256" || // Added in 7.0 2025f757f3fSDimitry Andric Name == "cvttps2dq.128" || // Added in 7.0 2035f757f3fSDimitry Andric Name == "cvttps2dq.256" || // Added in 7.0 2045f757f3fSDimitry Andric Name.starts_with("cvtudq2pd.") || // Added in 4.0 2055f757f3fSDimitry Andric Name.starts_with("cvtudq2ps.") || // Added in 7.0 updated 9.0 2065f757f3fSDimitry Andric Name.starts_with("cvtuqq2pd.") || // Added in 7.0 updated 9.0 2075f757f3fSDimitry Andric Name == "cvtuqq2ps.256" || // Added in 9.0 2085f757f3fSDimitry Andric Name == "cvtuqq2ps.512" || // Added in 9.0 2095f757f3fSDimitry Andric Name.starts_with("dbpsadbw.") || // Added in 7.0 2105f757f3fSDimitry Andric Name.starts_with("div.p") || // Added in 7.0. 128/256 in 4.0 2115f757f3fSDimitry Andric Name.starts_with("expand.b") || // Added in 9.0 2125f757f3fSDimitry Andric Name.starts_with("expand.d") || // Added in 9.0 2135f757f3fSDimitry Andric Name.starts_with("expand.load.") || // Added in 7.0 2145f757f3fSDimitry Andric Name.starts_with("expand.p") || // Added in 9.0 2155f757f3fSDimitry Andric Name.starts_with("expand.q") || // Added in 9.0 2165f757f3fSDimitry Andric Name.starts_with("expand.w") || // Added in 9.0 2175f757f3fSDimitry Andric Name.starts_with("fpclass.p") || // Added in 7.0 2185f757f3fSDimitry Andric Name.starts_with("insert") || // Added in 4.0 2195f757f3fSDimitry Andric Name.starts_with("load.") || // Added in 3.9 2205f757f3fSDimitry Andric Name.starts_with("loadu.") || // Added in 3.9 2215f757f3fSDimitry Andric Name.starts_with("lzcnt.") || // Added in 5.0 2225f757f3fSDimitry Andric Name.starts_with("max.p") || // Added in 7.0. 128/256 in 5.0 2235f757f3fSDimitry Andric Name.starts_with("min.p") || // Added in 7.0. 128/256 in 5.0 2245f757f3fSDimitry Andric Name.starts_with("movddup") || // Added in 3.9 2255f757f3fSDimitry Andric Name.starts_with("move.s") || // Added in 4.0 2265f757f3fSDimitry Andric Name.starts_with("movshdup") || // Added in 3.9 2275f757f3fSDimitry Andric Name.starts_with("movsldup") || // Added in 3.9 2285f757f3fSDimitry Andric Name.starts_with("mul.p") || // Added in 7.0. 128/256 in 4.0 2295f757f3fSDimitry Andric Name.starts_with("or.") || // Added in 3.9 2305f757f3fSDimitry Andric Name.starts_with("pabs.") || // Added in 6.0 2315f757f3fSDimitry Andric Name.starts_with("packssdw.") || // Added in 5.0 2325f757f3fSDimitry Andric Name.starts_with("packsswb.") || // Added in 5.0 2335f757f3fSDimitry Andric Name.starts_with("packusdw.") || // Added in 5.0 2345f757f3fSDimitry Andric Name.starts_with("packuswb.") || // Added in 5.0 2355f757f3fSDimitry Andric Name.starts_with("padd.") || // Added in 4.0 2365f757f3fSDimitry Andric Name.starts_with("padds.") || // Added in 8.0 2375f757f3fSDimitry Andric Name.starts_with("paddus.") || // Added in 8.0 2385f757f3fSDimitry Andric Name.starts_with("palignr.") || // Added in 3.9 2395f757f3fSDimitry Andric Name.starts_with("pand.") || // Added in 3.9 2405f757f3fSDimitry Andric Name.starts_with("pandn.") || // Added in 3.9 2415f757f3fSDimitry Andric Name.starts_with("pavg") || // Added in 6.0 2425f757f3fSDimitry Andric Name.starts_with("pbroadcast") || // Added in 6.0 2435f757f3fSDimitry Andric Name.starts_with("pcmpeq.") || // Added in 3.9 2445f757f3fSDimitry Andric Name.starts_with("pcmpgt.") || // Added in 3.9 2455f757f3fSDimitry Andric Name.starts_with("perm.df.") || // Added in 3.9 2465f757f3fSDimitry Andric Name.starts_with("perm.di.") || // Added in 3.9 2475f757f3fSDimitry Andric Name.starts_with("permvar.") || // Added in 7.0 2485f757f3fSDimitry Andric Name.starts_with("pmaddubs.w.") || // Added in 7.0 2495f757f3fSDimitry Andric Name.starts_with("pmaddw.d.") || // Added in 7.0 2505f757f3fSDimitry Andric Name.starts_with("pmax") || // Added in 4.0 2515f757f3fSDimitry Andric Name.starts_with("pmin") || // Added in 4.0 2525f757f3fSDimitry Andric Name == "pmov.qd.256" || // Added in 9.0 2535f757f3fSDimitry Andric Name == "pmov.qd.512" || // Added in 9.0 2545f757f3fSDimitry Andric Name == "pmov.wb.256" || // Added in 9.0 2555f757f3fSDimitry Andric Name == "pmov.wb.512" || // Added in 9.0 2565f757f3fSDimitry Andric Name.starts_with("pmovsx") || // Added in 4.0 2575f757f3fSDimitry Andric Name.starts_with("pmovzx") || // Added in 4.0 2585f757f3fSDimitry Andric Name.starts_with("pmul.dq.") || // Added in 4.0 2595f757f3fSDimitry Andric Name.starts_with("pmul.hr.sw.") || // Added in 7.0 2605f757f3fSDimitry Andric Name.starts_with("pmulh.w.") || // Added in 7.0 2615f757f3fSDimitry Andric Name.starts_with("pmulhu.w.") || // Added in 7.0 2625f757f3fSDimitry Andric Name.starts_with("pmull.") || // Added in 4.0 2635f757f3fSDimitry Andric Name.starts_with("pmultishift.qb.") || // Added in 8.0 2645f757f3fSDimitry Andric Name.starts_with("pmulu.dq.") || // Added in 4.0 2655f757f3fSDimitry Andric Name.starts_with("por.") || // Added in 3.9 2665f757f3fSDimitry Andric Name.starts_with("prol.") || // Added in 8.0 2675f757f3fSDimitry Andric Name.starts_with("prolv.") || // Added in 8.0 2685f757f3fSDimitry Andric Name.starts_with("pror.") || // Added in 8.0 2695f757f3fSDimitry Andric Name.starts_with("prorv.") || // Added in 8.0 2705f757f3fSDimitry Andric Name.starts_with("pshuf.b.") || // Added in 4.0 2715f757f3fSDimitry Andric Name.starts_with("pshuf.d.") || // Added in 3.9 2725f757f3fSDimitry Andric Name.starts_with("pshufh.w.") || // Added in 3.9 2735f757f3fSDimitry Andric Name.starts_with("pshufl.w.") || // Added in 3.9 2745f757f3fSDimitry Andric Name.starts_with("psll.d") || // Added in 4.0 2755f757f3fSDimitry Andric Name.starts_with("psll.q") || // Added in 4.0 2765f757f3fSDimitry Andric Name.starts_with("psll.w") || // Added in 4.0 2775f757f3fSDimitry Andric Name.starts_with("pslli") || // Added in 4.0 2785f757f3fSDimitry Andric Name.starts_with("psllv") || // Added in 4.0 2795f757f3fSDimitry Andric Name.starts_with("psra.d") || // Added in 4.0 2805f757f3fSDimitry Andric Name.starts_with("psra.q") || // Added in 4.0 2815f757f3fSDimitry Andric Name.starts_with("psra.w") || // Added in 4.0 2825f757f3fSDimitry Andric Name.starts_with("psrai") || // Added in 4.0 2835f757f3fSDimitry Andric Name.starts_with("psrav") || // Added in 4.0 2845f757f3fSDimitry Andric Name.starts_with("psrl.d") || // Added in 4.0 2855f757f3fSDimitry Andric Name.starts_with("psrl.q") || // Added in 4.0 2865f757f3fSDimitry Andric Name.starts_with("psrl.w") || // Added in 4.0 2875f757f3fSDimitry Andric Name.starts_with("psrli") || // Added in 4.0 2885f757f3fSDimitry Andric Name.starts_with("psrlv") || // Added in 4.0 2895f757f3fSDimitry Andric Name.starts_with("psub.") || // Added in 4.0 2905f757f3fSDimitry Andric Name.starts_with("psubs.") || // Added in 8.0 2915f757f3fSDimitry Andric Name.starts_with("psubus.") || // Added in 8.0 2925f757f3fSDimitry Andric Name.starts_with("pternlog.") || // Added in 7.0 2935f757f3fSDimitry Andric Name.starts_with("punpckh") || // Added in 3.9 2945f757f3fSDimitry Andric Name.starts_with("punpckl") || // Added in 3.9 2955f757f3fSDimitry Andric Name.starts_with("pxor.") || // Added in 3.9 2965f757f3fSDimitry Andric Name.starts_with("shuf.f") || // Added in 6.0 2975f757f3fSDimitry Andric Name.starts_with("shuf.i") || // Added in 6.0 2985f757f3fSDimitry Andric Name.starts_with("shuf.p") || // Added in 4.0 2995f757f3fSDimitry Andric Name.starts_with("sqrt.p") || // Added in 7.0 3005f757f3fSDimitry Andric Name.starts_with("store.b.") || // Added in 3.9 3015f757f3fSDimitry Andric Name.starts_with("store.d.") || // Added in 3.9 3025f757f3fSDimitry Andric Name.starts_with("store.p") || // Added in 3.9 3035f757f3fSDimitry Andric Name.starts_with("store.q.") || // Added in 3.9 3045f757f3fSDimitry Andric Name.starts_with("store.w.") || // Added in 3.9 3055f757f3fSDimitry Andric Name == "store.ss" || // Added in 7.0 3065f757f3fSDimitry Andric Name.starts_with("storeu.") || // Added in 3.9 3075f757f3fSDimitry Andric Name.starts_with("sub.p") || // Added in 7.0. 128/256 in 4.0 3085f757f3fSDimitry Andric Name.starts_with("ucmp.") || // Added in 5.0 3095f757f3fSDimitry Andric Name.starts_with("unpckh.") || // Added in 3.9 3105f757f3fSDimitry Andric Name.starts_with("unpckl.") || // Added in 3.9 3115f757f3fSDimitry Andric Name.starts_with("valign.") || // Added in 4.0 3125f757f3fSDimitry Andric Name == "vcvtph2ps.128" || // Added in 11.0 3135f757f3fSDimitry Andric Name == "vcvtph2ps.256" || // Added in 11.0 3145f757f3fSDimitry Andric Name.starts_with("vextract") || // Added in 4.0 3155f757f3fSDimitry Andric Name.starts_with("vfmadd.") || // Added in 7.0 3165f757f3fSDimitry Andric Name.starts_with("vfmaddsub.") || // Added in 7.0 3175f757f3fSDimitry Andric Name.starts_with("vfnmadd.") || // Added in 7.0 3185f757f3fSDimitry Andric Name.starts_with("vfnmsub.") || // Added in 7.0 3195f757f3fSDimitry Andric Name.starts_with("vpdpbusd.") || // Added in 7.0 3205f757f3fSDimitry Andric Name.starts_with("vpdpbusds.") || // Added in 7.0 3215f757f3fSDimitry Andric Name.starts_with("vpdpwssd.") || // Added in 7.0 3225f757f3fSDimitry Andric Name.starts_with("vpdpwssds.") || // Added in 7.0 3235f757f3fSDimitry Andric Name.starts_with("vpermi2var.") || // Added in 7.0 3245f757f3fSDimitry Andric Name.starts_with("vpermil.p") || // Added in 3.9 3255f757f3fSDimitry Andric Name.starts_with("vpermilvar.") || // Added in 4.0 3265f757f3fSDimitry Andric Name.starts_with("vpermt2var.") || // Added in 7.0 3275f757f3fSDimitry Andric Name.starts_with("vpmadd52") || // Added in 7.0 3285f757f3fSDimitry Andric Name.starts_with("vpshld.") || // Added in 7.0 3295f757f3fSDimitry Andric Name.starts_with("vpshldv.") || // Added in 8.0 3305f757f3fSDimitry Andric Name.starts_with("vpshrd.") || // Added in 7.0 3315f757f3fSDimitry Andric Name.starts_with("vpshrdv.") || // Added in 8.0 3325f757f3fSDimitry Andric Name.starts_with("vpshufbitqmb.") || // Added in 8.0 3335f757f3fSDimitry Andric Name.starts_with("xor.")); // Added in 3.9 3345f757f3fSDimitry Andric 3355f757f3fSDimitry Andric if (Name.consume_front("mask3.")) 3365f757f3fSDimitry Andric // 'avx512.mask3.*' 3375f757f3fSDimitry Andric return (Name.starts_with("vfmadd.") || // Added in 7.0 3385f757f3fSDimitry Andric Name.starts_with("vfmaddsub.") || // Added in 7.0 3395f757f3fSDimitry Andric Name.starts_with("vfmsub.") || // Added in 7.0 3405f757f3fSDimitry Andric Name.starts_with("vfmsubadd.") || // Added in 7.0 3415f757f3fSDimitry Andric Name.starts_with("vfnmsub.")); // Added in 7.0 3425f757f3fSDimitry Andric 3435f757f3fSDimitry Andric if (Name.consume_front("maskz.")) 3445f757f3fSDimitry Andric // 'avx512.maskz.*' 3455f757f3fSDimitry Andric return (Name.starts_with("pternlog.") || // Added in 7.0 3465f757f3fSDimitry Andric Name.starts_with("vfmadd.") || // Added in 7.0 3475f757f3fSDimitry Andric Name.starts_with("vfmaddsub.") || // Added in 7.0 3485f757f3fSDimitry Andric Name.starts_with("vpdpbusd.") || // Added in 7.0 3495f757f3fSDimitry Andric Name.starts_with("vpdpbusds.") || // Added in 7.0 3505f757f3fSDimitry Andric Name.starts_with("vpdpwssd.") || // Added in 7.0 3515f757f3fSDimitry Andric Name.starts_with("vpdpwssds.") || // Added in 7.0 3525f757f3fSDimitry Andric Name.starts_with("vpermt2var.") || // Added in 7.0 3535f757f3fSDimitry Andric Name.starts_with("vpmadd52") || // Added in 7.0 3545f757f3fSDimitry Andric Name.starts_with("vpshldv.") || // Added in 8.0 3555f757f3fSDimitry Andric Name.starts_with("vpshrdv.")); // Added in 8.0 3565f757f3fSDimitry Andric 3575f757f3fSDimitry Andric // 'avx512.*' 3585f757f3fSDimitry Andric return (Name == "movntdqa" || // Added in 5.0 3595f757f3fSDimitry Andric Name == "pmul.dq.512" || // Added in 7.0 3605f757f3fSDimitry Andric Name == "pmulu.dq.512" || // Added in 7.0 3615f757f3fSDimitry Andric Name.starts_with("broadcastm") || // Added in 6.0 3625f757f3fSDimitry Andric Name.starts_with("cmp.p") || // Added in 12.0 3635f757f3fSDimitry Andric Name.starts_with("cvtb2mask.") || // Added in 7.0 3645f757f3fSDimitry Andric Name.starts_with("cvtd2mask.") || // Added in 7.0 3655f757f3fSDimitry Andric Name.starts_with("cvtmask2") || // Added in 5.0 3665f757f3fSDimitry Andric Name.starts_with("cvtq2mask.") || // Added in 7.0 3675f757f3fSDimitry Andric Name == "cvtusi2sd" || // Added in 7.0 3685f757f3fSDimitry Andric Name.starts_with("cvtw2mask.") || // Added in 7.0 3695f757f3fSDimitry Andric Name == "kand.w" || // Added in 7.0 3705f757f3fSDimitry Andric Name == "kandn.w" || // Added in 7.0 3715f757f3fSDimitry Andric Name == "knot.w" || // Added in 7.0 3725f757f3fSDimitry Andric Name == "kor.w" || // Added in 7.0 3735f757f3fSDimitry Andric Name == "kortestc.w" || // Added in 7.0 3745f757f3fSDimitry Andric Name == "kortestz.w" || // Added in 7.0 3755f757f3fSDimitry Andric Name.starts_with("kunpck") || // added in 6.0 3765f757f3fSDimitry Andric Name == "kxnor.w" || // Added in 7.0 3775f757f3fSDimitry Andric Name == "kxor.w" || // Added in 7.0 3785f757f3fSDimitry Andric Name.starts_with("padds.") || // Added in 8.0 3795f757f3fSDimitry Andric Name.starts_with("pbroadcast") || // Added in 3.9 3805f757f3fSDimitry Andric Name.starts_with("prol") || // Added in 8.0 3815f757f3fSDimitry Andric Name.starts_with("pror") || // Added in 8.0 3825f757f3fSDimitry Andric Name.starts_with("psll.dq") || // Added in 3.9 3835f757f3fSDimitry Andric Name.starts_with("psrl.dq") || // Added in 3.9 3845f757f3fSDimitry Andric Name.starts_with("psubs.") || // Added in 8.0 3855f757f3fSDimitry Andric Name.starts_with("ptestm") || // Added in 6.0 3865f757f3fSDimitry Andric Name.starts_with("ptestnm") || // Added in 6.0 3875f757f3fSDimitry Andric Name.starts_with("storent.") || // Added in 3.9 3885f757f3fSDimitry Andric Name.starts_with("vbroadcast.s") || // Added in 7.0 3895f757f3fSDimitry Andric Name.starts_with("vpshld.") || // Added in 8.0 3905f757f3fSDimitry Andric Name.starts_with("vpshrd.")); // Added in 8.0 3915f757f3fSDimitry Andric } 3925f757f3fSDimitry Andric 3935f757f3fSDimitry Andric if (Name.consume_front("fma.")) 3945f757f3fSDimitry Andric return (Name.starts_with("vfmadd.") || // Added in 7.0 3955f757f3fSDimitry Andric Name.starts_with("vfmsub.") || // Added in 7.0 3965f757f3fSDimitry Andric Name.starts_with("vfmsubadd.") || // Added in 7.0 3975f757f3fSDimitry Andric Name.starts_with("vfnmadd.") || // Added in 7.0 3985f757f3fSDimitry Andric Name.starts_with("vfnmsub.")); // Added in 7.0 3995f757f3fSDimitry Andric 4005f757f3fSDimitry Andric if (Name.consume_front("fma4.")) 4015f757f3fSDimitry Andric return Name.starts_with("vfmadd.s"); // Added in 7.0 4025f757f3fSDimitry Andric 4035f757f3fSDimitry Andric if (Name.consume_front("sse.")) 4045f757f3fSDimitry Andric return (Name == "add.ss" || // Added in 4.0 4055f757f3fSDimitry Andric Name == "cvtsi2ss" || // Added in 7.0 4065f757f3fSDimitry Andric Name == "cvtsi642ss" || // Added in 7.0 4075f757f3fSDimitry Andric Name == "div.ss" || // Added in 4.0 4085f757f3fSDimitry Andric Name == "mul.ss" || // Added in 4.0 4095f757f3fSDimitry Andric Name.starts_with("sqrt.p") || // Added in 7.0 4105f757f3fSDimitry Andric Name == "sqrt.ss" || // Added in 7.0 4115f757f3fSDimitry Andric Name.starts_with("storeu.") || // Added in 3.9 4125f757f3fSDimitry Andric Name == "sub.ss"); // Added in 4.0 4135f757f3fSDimitry Andric 4145f757f3fSDimitry Andric if (Name.consume_front("sse2.")) 4155f757f3fSDimitry Andric return (Name == "add.sd" || // Added in 4.0 4165f757f3fSDimitry Andric Name == "cvtdq2pd" || // Added in 3.9 4175f757f3fSDimitry Andric Name == "cvtdq2ps" || // Added in 7.0 4185f757f3fSDimitry Andric Name == "cvtps2pd" || // Added in 3.9 4195f757f3fSDimitry Andric Name == "cvtsi2sd" || // Added in 7.0 4205f757f3fSDimitry Andric Name == "cvtsi642sd" || // Added in 7.0 4215f757f3fSDimitry Andric Name == "cvtss2sd" || // Added in 7.0 4225f757f3fSDimitry Andric Name == "div.sd" || // Added in 4.0 4235f757f3fSDimitry Andric Name == "mul.sd" || // Added in 4.0 4245f757f3fSDimitry Andric Name.starts_with("padds.") || // Added in 8.0 4255f757f3fSDimitry Andric Name.starts_with("paddus.") || // Added in 8.0 4265f757f3fSDimitry Andric Name.starts_with("pcmpeq.") || // Added in 3.1 4275f757f3fSDimitry Andric Name.starts_with("pcmpgt.") || // Added in 3.1 4285f757f3fSDimitry Andric Name == "pmaxs.w" || // Added in 3.9 4295f757f3fSDimitry Andric Name == "pmaxu.b" || // Added in 3.9 4305f757f3fSDimitry Andric Name == "pmins.w" || // Added in 3.9 4315f757f3fSDimitry Andric Name == "pminu.b" || // Added in 3.9 4325f757f3fSDimitry Andric Name == "pmulu.dq" || // Added in 7.0 4335f757f3fSDimitry Andric Name.starts_with("pshuf") || // Added in 3.9 4345f757f3fSDimitry Andric Name.starts_with("psll.dq") || // Added in 3.7 4355f757f3fSDimitry Andric Name.starts_with("psrl.dq") || // Added in 3.7 4365f757f3fSDimitry Andric Name.starts_with("psubs.") || // Added in 8.0 4375f757f3fSDimitry Andric Name.starts_with("psubus.") || // Added in 8.0 4385f757f3fSDimitry Andric Name.starts_with("sqrt.p") || // Added in 7.0 4395f757f3fSDimitry Andric Name == "sqrt.sd" || // Added in 7.0 4405f757f3fSDimitry Andric Name == "storel.dq" || // Added in 3.9 4415f757f3fSDimitry Andric Name.starts_with("storeu.") || // Added in 3.9 4425f757f3fSDimitry Andric Name == "sub.sd"); // Added in 4.0 4435f757f3fSDimitry Andric 4445f757f3fSDimitry Andric if (Name.consume_front("sse41.")) 4455f757f3fSDimitry Andric return (Name.starts_with("blendp") || // Added in 3.7 4465f757f3fSDimitry Andric Name == "movntdqa" || // Added in 5.0 4475f757f3fSDimitry Andric Name == "pblendw" || // Added in 3.7 4485f757f3fSDimitry Andric Name == "pmaxsb" || // Added in 3.9 4495f757f3fSDimitry Andric Name == "pmaxsd" || // Added in 3.9 4505f757f3fSDimitry Andric Name == "pmaxud" || // Added in 3.9 4515f757f3fSDimitry Andric Name == "pmaxuw" || // Added in 3.9 4525f757f3fSDimitry Andric Name == "pminsb" || // Added in 3.9 4535f757f3fSDimitry Andric Name == "pminsd" || // Added in 3.9 4545f757f3fSDimitry Andric Name == "pminud" || // Added in 3.9 4555f757f3fSDimitry Andric Name == "pminuw" || // Added in 3.9 4565f757f3fSDimitry Andric Name.starts_with("pmovsx") || // Added in 3.8 4575f757f3fSDimitry Andric Name.starts_with("pmovzx") || // Added in 3.9 4585f757f3fSDimitry Andric Name == "pmuldq"); // Added in 7.0 4595f757f3fSDimitry Andric 4605f757f3fSDimitry Andric if (Name.consume_front("sse42.")) 4615f757f3fSDimitry Andric return Name == "crc32.64.8"; // Added in 3.4 4625f757f3fSDimitry Andric 4635f757f3fSDimitry Andric if (Name.consume_front("sse4a.")) 4645f757f3fSDimitry Andric return Name.starts_with("movnt."); // Added in 3.9 4655f757f3fSDimitry Andric 4665f757f3fSDimitry Andric if (Name.consume_front("ssse3.")) 4675f757f3fSDimitry Andric return (Name == "pabs.b.128" || // Added in 6.0 4685f757f3fSDimitry Andric Name == "pabs.d.128" || // Added in 6.0 4695f757f3fSDimitry Andric Name == "pabs.w.128"); // Added in 6.0 4705f757f3fSDimitry Andric 4715f757f3fSDimitry Andric if (Name.consume_front("xop.")) 4725f757f3fSDimitry Andric return (Name == "vpcmov" || // Added in 3.8 4735f757f3fSDimitry Andric Name == "vpcmov.256" || // Added in 5.0 4745f757f3fSDimitry Andric Name.starts_with("vpcom") || // Added in 3.2, Updated in 9.0 4755f757f3fSDimitry Andric Name.starts_with("vprot")); // Added in 8.0 4765f757f3fSDimitry Andric 4775f757f3fSDimitry Andric return (Name == "addcarry.u32" || // Added in 8.0 4780b57cec5SDimitry Andric Name == "addcarry.u64" || // Added in 8.0 4795f757f3fSDimitry Andric Name == "addcarryx.u32" || // Added in 8.0 4805f757f3fSDimitry Andric Name == "addcarryx.u64" || // Added in 8.0 4810b57cec5SDimitry Andric Name == "subborrow.u32" || // Added in 8.0 4820b57cec5SDimitry Andric Name == "subborrow.u64" || // Added in 8.0 4835f757f3fSDimitry Andric Name.starts_with("vcvtph2ps.")); // Added in 11.0 4840b57cec5SDimitry Andric } 4850b57cec5SDimitry Andric 4867a6dacacSDimitry Andric static bool upgradeX86IntrinsicFunction(Function *F, StringRef Name, 4870b57cec5SDimitry Andric Function *&NewFn) { 4880b57cec5SDimitry Andric // Only handle intrinsics that start with "x86.". 4895f757f3fSDimitry Andric if (!Name.consume_front("x86.")) 4900b57cec5SDimitry Andric return false; 4910b57cec5SDimitry Andric 4927a6dacacSDimitry Andric if (shouldUpgradeX86Intrinsic(F, Name)) { 4930b57cec5SDimitry Andric NewFn = nullptr; 4940b57cec5SDimitry Andric return true; 4950b57cec5SDimitry Andric } 4960b57cec5SDimitry Andric 4970b57cec5SDimitry Andric if (Name == "rdtscp") { // Added in 8.0 4980b57cec5SDimitry Andric // If this intrinsic has 0 operands, it's the new version. 4990b57cec5SDimitry Andric if (F->getFunctionType()->getNumParams() == 0) 5000b57cec5SDimitry Andric return false; 5010b57cec5SDimitry Andric 5020b57cec5SDimitry Andric rename(F); 5030b57cec5SDimitry Andric NewFn = Intrinsic::getDeclaration(F->getParent(), 5040b57cec5SDimitry Andric Intrinsic::x86_rdtscp); 5050b57cec5SDimitry Andric return true; 5060b57cec5SDimitry Andric } 5070b57cec5SDimitry Andric 5085f757f3fSDimitry Andric Intrinsic::ID ID; 5095f757f3fSDimitry Andric 5100b57cec5SDimitry Andric // SSE4.1 ptest functions may have an old signature. 5115f757f3fSDimitry Andric if (Name.consume_front("sse41.ptest")) { // Added in 3.2 5125f757f3fSDimitry Andric ID = StringSwitch<Intrinsic::ID>(Name) 5135f757f3fSDimitry Andric .Case("c", Intrinsic::x86_sse41_ptestc) 5145f757f3fSDimitry Andric .Case("z", Intrinsic::x86_sse41_ptestz) 5155f757f3fSDimitry Andric .Case("nzc", Intrinsic::x86_sse41_ptestnzc) 5165f757f3fSDimitry Andric .Default(Intrinsic::not_intrinsic); 5175f757f3fSDimitry Andric if (ID != Intrinsic::not_intrinsic) 5187a6dacacSDimitry Andric return upgradePTESTIntrinsic(F, ID, NewFn); 5195f757f3fSDimitry Andric 5205f757f3fSDimitry Andric return false; 5210b57cec5SDimitry Andric } 5225f757f3fSDimitry Andric 5230b57cec5SDimitry Andric // Several blend and other instructions with masks used the wrong number of 5240b57cec5SDimitry Andric // bits. 5250b57cec5SDimitry Andric 5265f757f3fSDimitry Andric // Added in 3.6 5275f757f3fSDimitry Andric ID = StringSwitch<Intrinsic::ID>(Name) 5285f757f3fSDimitry Andric .Case("sse41.insertps", Intrinsic::x86_sse41_insertps) 5295f757f3fSDimitry Andric .Case("sse41.dppd", Intrinsic::x86_sse41_dppd) 5305f757f3fSDimitry Andric .Case("sse41.dpps", Intrinsic::x86_sse41_dpps) 5315f757f3fSDimitry Andric .Case("sse41.mpsadbw", Intrinsic::x86_sse41_mpsadbw) 5325f757f3fSDimitry Andric .Case("avx.dp.ps.256", Intrinsic::x86_avx_dp_ps_256) 5335f757f3fSDimitry Andric .Case("avx2.mpsadbw", Intrinsic::x86_avx2_mpsadbw) 5345f757f3fSDimitry Andric .Default(Intrinsic::not_intrinsic); 5355f757f3fSDimitry Andric if (ID != Intrinsic::not_intrinsic) 5367a6dacacSDimitry Andric return upgradeX86IntrinsicsWith8BitMask(F, ID, NewFn); 5375f757f3fSDimitry Andric 5385f757f3fSDimitry Andric if (Name.consume_front("avx512.mask.cmp.")) { 5395f757f3fSDimitry Andric // Added in 7.0 5405f757f3fSDimitry Andric ID = StringSwitch<Intrinsic::ID>(Name) 5415f757f3fSDimitry Andric .Case("pd.128", Intrinsic::x86_avx512_mask_cmp_pd_128) 5425f757f3fSDimitry Andric .Case("pd.256", Intrinsic::x86_avx512_mask_cmp_pd_256) 5435f757f3fSDimitry Andric .Case("pd.512", Intrinsic::x86_avx512_mask_cmp_pd_512) 5445f757f3fSDimitry Andric .Case("ps.128", Intrinsic::x86_avx512_mask_cmp_ps_128) 5455f757f3fSDimitry Andric .Case("ps.256", Intrinsic::x86_avx512_mask_cmp_ps_256) 5465f757f3fSDimitry Andric .Case("ps.512", Intrinsic::x86_avx512_mask_cmp_ps_512) 5475f757f3fSDimitry Andric .Default(Intrinsic::not_intrinsic); 5485f757f3fSDimitry Andric if (ID != Intrinsic::not_intrinsic) 5497a6dacacSDimitry Andric return upgradeX86MaskedFPCompare(F, ID, NewFn); 5505f757f3fSDimitry Andric return false; // No other 'x86.avx523.mask.cmp.*'. 5510b57cec5SDimitry Andric } 5525f757f3fSDimitry Andric 5535f757f3fSDimitry Andric if (Name.consume_front("avx512bf16.")) { 5545f757f3fSDimitry Andric // Added in 9.0 5555f757f3fSDimitry Andric ID = StringSwitch<Intrinsic::ID>(Name) 5565f757f3fSDimitry Andric .Case("cvtne2ps2bf16.128", 5575f757f3fSDimitry Andric Intrinsic::x86_avx512bf16_cvtne2ps2bf16_128) 5585f757f3fSDimitry Andric .Case("cvtne2ps2bf16.256", 5595f757f3fSDimitry Andric Intrinsic::x86_avx512bf16_cvtne2ps2bf16_256) 5605f757f3fSDimitry Andric .Case("cvtne2ps2bf16.512", 5615f757f3fSDimitry Andric Intrinsic::x86_avx512bf16_cvtne2ps2bf16_512) 5625f757f3fSDimitry Andric .Case("mask.cvtneps2bf16.128", 5635f757f3fSDimitry Andric Intrinsic::x86_avx512bf16_mask_cvtneps2bf16_128) 5645f757f3fSDimitry Andric .Case("cvtneps2bf16.256", 5655f757f3fSDimitry Andric Intrinsic::x86_avx512bf16_cvtneps2bf16_256) 5665f757f3fSDimitry Andric .Case("cvtneps2bf16.512", 5675f757f3fSDimitry Andric Intrinsic::x86_avx512bf16_cvtneps2bf16_512) 5685f757f3fSDimitry Andric .Default(Intrinsic::not_intrinsic); 5695f757f3fSDimitry Andric if (ID != Intrinsic::not_intrinsic) 5707a6dacacSDimitry Andric return upgradeX86BF16Intrinsic(F, ID, NewFn); 5715f757f3fSDimitry Andric 5725f757f3fSDimitry Andric // Added in 9.0 5735f757f3fSDimitry Andric ID = StringSwitch<Intrinsic::ID>(Name) 5745f757f3fSDimitry Andric .Case("dpbf16ps.128", Intrinsic::x86_avx512bf16_dpbf16ps_128) 5755f757f3fSDimitry Andric .Case("dpbf16ps.256", Intrinsic::x86_avx512bf16_dpbf16ps_256) 5765f757f3fSDimitry Andric .Case("dpbf16ps.512", Intrinsic::x86_avx512bf16_dpbf16ps_512) 5775f757f3fSDimitry Andric .Default(Intrinsic::not_intrinsic); 5785f757f3fSDimitry Andric if (ID != Intrinsic::not_intrinsic) 5797a6dacacSDimitry Andric return upgradeX86BF16DPIntrinsic(F, ID, NewFn); 5805f757f3fSDimitry Andric return false; // No other 'x86.avx512bf16.*'. 5810b57cec5SDimitry Andric } 5825f757f3fSDimitry Andric 5835f757f3fSDimitry Andric if (Name.consume_front("xop.")) { 5845f757f3fSDimitry Andric Intrinsic::ID ID = Intrinsic::not_intrinsic; 5855f757f3fSDimitry Andric if (Name.starts_with("vpermil2")) { // Added in 3.9 5865f757f3fSDimitry Andric // Upgrade any XOP PERMIL2 index operand still using a float/double 5875f757f3fSDimitry Andric // vector. 5880b57cec5SDimitry Andric auto Idx = F->getFunctionType()->getParamType(2); 5890b57cec5SDimitry Andric if (Idx->isFPOrFPVectorTy()) { 5900b57cec5SDimitry Andric unsigned IdxSize = Idx->getPrimitiveSizeInBits(); 5910b57cec5SDimitry Andric unsigned EltSize = Idx->getScalarSizeInBits(); 5920b57cec5SDimitry Andric if (EltSize == 64 && IdxSize == 128) 5935f757f3fSDimitry Andric ID = Intrinsic::x86_xop_vpermil2pd; 5940b57cec5SDimitry Andric else if (EltSize == 32 && IdxSize == 128) 5955f757f3fSDimitry Andric ID = Intrinsic::x86_xop_vpermil2ps; 5960b57cec5SDimitry Andric else if (EltSize == 64 && IdxSize == 256) 5975f757f3fSDimitry Andric ID = Intrinsic::x86_xop_vpermil2pd_256; 5980b57cec5SDimitry Andric else 5995f757f3fSDimitry Andric ID = Intrinsic::x86_xop_vpermil2ps_256; 6005f757f3fSDimitry Andric } 6015f757f3fSDimitry Andric } else if (F->arg_size() == 2) 6025f757f3fSDimitry Andric // frcz.ss/sd may need to have an argument dropped. Added in 3.2 6035f757f3fSDimitry Andric ID = StringSwitch<Intrinsic::ID>(Name) 6045f757f3fSDimitry Andric .Case("vfrcz.ss", Intrinsic::x86_xop_vfrcz_ss) 6055f757f3fSDimitry Andric .Case("vfrcz.sd", Intrinsic::x86_xop_vfrcz_sd) 6065f757f3fSDimitry Andric .Default(Intrinsic::not_intrinsic); 6075f757f3fSDimitry Andric 6085f757f3fSDimitry Andric if (ID != Intrinsic::not_intrinsic) { 6095f757f3fSDimitry Andric rename(F); 6105f757f3fSDimitry Andric NewFn = Intrinsic::getDeclaration(F->getParent(), ID); 6110b57cec5SDimitry Andric return true; 6120b57cec5SDimitry Andric } 6135f757f3fSDimitry Andric return false; // No other 'x86.xop.*' 6140b57cec5SDimitry Andric } 6150b57cec5SDimitry Andric 6160b57cec5SDimitry Andric if (Name == "seh.recoverfp") { 6170b57cec5SDimitry Andric NewFn = Intrinsic::getDeclaration(F->getParent(), Intrinsic::eh_recoverfp); 6180b57cec5SDimitry Andric return true; 6190b57cec5SDimitry Andric } 6200b57cec5SDimitry Andric 6210b57cec5SDimitry Andric return false; 6220b57cec5SDimitry Andric } 6230b57cec5SDimitry Andric 6241db9f3b2SDimitry Andric // Upgrade ARM (IsArm) or Aarch64 (!IsArm) intrinsic fns. Return true iff so. 6251db9f3b2SDimitry Andric // IsArm: 'arm.*', !IsArm: 'aarch64.*'. 6267a6dacacSDimitry Andric static bool upgradeArmOrAarch64IntrinsicFunction(bool IsArm, Function *F, 6271db9f3b2SDimitry Andric StringRef Name, 6281db9f3b2SDimitry Andric Function *&NewFn) { 6291db9f3b2SDimitry Andric if (Name.starts_with("rbit")) { 6301db9f3b2SDimitry Andric // '(arm|aarch64).rbit'. 6311db9f3b2SDimitry Andric NewFn = Intrinsic::getDeclaration(F->getParent(), Intrinsic::bitreverse, 6321db9f3b2SDimitry Andric F->arg_begin()->getType()); 6331db9f3b2SDimitry Andric return true; 6341db9f3b2SDimitry Andric } 6351db9f3b2SDimitry Andric 6361db9f3b2SDimitry Andric if (Name == "thread.pointer") { 6371db9f3b2SDimitry Andric // '(arm|aarch64).thread.pointer'. 6381db9f3b2SDimitry Andric NewFn = 6391db9f3b2SDimitry Andric Intrinsic::getDeclaration(F->getParent(), Intrinsic::thread_pointer); 6401db9f3b2SDimitry Andric return true; 6411db9f3b2SDimitry Andric } 6421db9f3b2SDimitry Andric 6431db9f3b2SDimitry Andric bool Neon = Name.consume_front("neon."); 6441db9f3b2SDimitry Andric if (Neon) { 6451db9f3b2SDimitry Andric // '(arm|aarch64).neon.*'. 6461db9f3b2SDimitry Andric // Changed in 12.0: bfdot accept v4bf16 and v8bf16 instead of v8i8 and 6471db9f3b2SDimitry Andric // v16i8 respectively. 6481db9f3b2SDimitry Andric if (Name.consume_front("bfdot.")) { 6491db9f3b2SDimitry Andric // (arm|aarch64).neon.bfdot.*'. 650*0fca6ea1SDimitry Andric Intrinsic::ID ID = 651*0fca6ea1SDimitry Andric StringSwitch<Intrinsic::ID>(Name) 6521db9f3b2SDimitry Andric .Cases("v2f32.v8i8", "v4f32.v16i8", 653*0fca6ea1SDimitry Andric IsArm ? (Intrinsic::ID)Intrinsic::arm_neon_bfdot 654*0fca6ea1SDimitry Andric : (Intrinsic::ID)Intrinsic::aarch64_neon_bfdot) 6551db9f3b2SDimitry Andric .Default(Intrinsic::not_intrinsic); 6561db9f3b2SDimitry Andric if (ID != Intrinsic::not_intrinsic) { 6571db9f3b2SDimitry Andric size_t OperandWidth = F->getReturnType()->getPrimitiveSizeInBits(); 6581db9f3b2SDimitry Andric assert((OperandWidth == 64 || OperandWidth == 128) && 6591db9f3b2SDimitry Andric "Unexpected operand width"); 6601db9f3b2SDimitry Andric LLVMContext &Ctx = F->getParent()->getContext(); 6611db9f3b2SDimitry Andric std::array<Type *, 2> Tys{ 6621db9f3b2SDimitry Andric {F->getReturnType(), 6631db9f3b2SDimitry Andric FixedVectorType::get(Type::getBFloatTy(Ctx), OperandWidth / 16)}}; 6641db9f3b2SDimitry Andric NewFn = Intrinsic::getDeclaration(F->getParent(), ID, Tys); 6651db9f3b2SDimitry Andric return true; 6661db9f3b2SDimitry Andric } 6671db9f3b2SDimitry Andric return false; // No other '(arm|aarch64).neon.bfdot.*'. 6681db9f3b2SDimitry Andric } 6691db9f3b2SDimitry Andric 6701db9f3b2SDimitry Andric // Changed in 12.0: bfmmla, bfmlalb and bfmlalt are not polymorphic 6711db9f3b2SDimitry Andric // anymore and accept v8bf16 instead of v16i8. 6721db9f3b2SDimitry Andric if (Name.consume_front("bfm")) { 6731db9f3b2SDimitry Andric // (arm|aarch64).neon.bfm*'. 6741db9f3b2SDimitry Andric if (Name.consume_back(".v4f32.v16i8")) { 6751db9f3b2SDimitry Andric // (arm|aarch64).neon.bfm*.v4f32.v16i8'. 6761db9f3b2SDimitry Andric Intrinsic::ID ID = 6771db9f3b2SDimitry Andric StringSwitch<Intrinsic::ID>(Name) 678*0fca6ea1SDimitry Andric .Case("mla", 679*0fca6ea1SDimitry Andric IsArm ? (Intrinsic::ID)Intrinsic::arm_neon_bfmmla 680*0fca6ea1SDimitry Andric : (Intrinsic::ID)Intrinsic::aarch64_neon_bfmmla) 681*0fca6ea1SDimitry Andric .Case("lalb", 682*0fca6ea1SDimitry Andric IsArm ? (Intrinsic::ID)Intrinsic::arm_neon_bfmlalb 683*0fca6ea1SDimitry Andric : (Intrinsic::ID)Intrinsic::aarch64_neon_bfmlalb) 684*0fca6ea1SDimitry Andric .Case("lalt", 685*0fca6ea1SDimitry Andric IsArm ? (Intrinsic::ID)Intrinsic::arm_neon_bfmlalt 686*0fca6ea1SDimitry Andric : (Intrinsic::ID)Intrinsic::aarch64_neon_bfmlalt) 6871db9f3b2SDimitry Andric .Default(Intrinsic::not_intrinsic); 6881db9f3b2SDimitry Andric if (ID != Intrinsic::not_intrinsic) { 6891db9f3b2SDimitry Andric NewFn = Intrinsic::getDeclaration(F->getParent(), ID); 6901db9f3b2SDimitry Andric return true; 6911db9f3b2SDimitry Andric } 6921db9f3b2SDimitry Andric return false; // No other '(arm|aarch64).neon.bfm*.v16i8'. 6931db9f3b2SDimitry Andric } 6941db9f3b2SDimitry Andric return false; // No other '(arm|aarch64).neon.bfm*. 6951db9f3b2SDimitry Andric } 6961db9f3b2SDimitry Andric // Continue on to Aarch64 Neon or Arm Neon. 6971db9f3b2SDimitry Andric } 6981db9f3b2SDimitry Andric // Continue on to Arm or Aarch64. 6991db9f3b2SDimitry Andric 7001db9f3b2SDimitry Andric if (IsArm) { 7011db9f3b2SDimitry Andric // 'arm.*'. 7021db9f3b2SDimitry Andric if (Neon) { 7031db9f3b2SDimitry Andric // 'arm.neon.*'. 7041db9f3b2SDimitry Andric Intrinsic::ID ID = StringSwitch<Intrinsic::ID>(Name) 7051db9f3b2SDimitry Andric .StartsWith("vclz.", Intrinsic::ctlz) 7061db9f3b2SDimitry Andric .StartsWith("vcnt.", Intrinsic::ctpop) 7071db9f3b2SDimitry Andric .StartsWith("vqadds.", Intrinsic::sadd_sat) 7081db9f3b2SDimitry Andric .StartsWith("vqaddu.", Intrinsic::uadd_sat) 7091db9f3b2SDimitry Andric .StartsWith("vqsubs.", Intrinsic::ssub_sat) 7101db9f3b2SDimitry Andric .StartsWith("vqsubu.", Intrinsic::usub_sat) 7111db9f3b2SDimitry Andric .Default(Intrinsic::not_intrinsic); 7121db9f3b2SDimitry Andric if (ID != Intrinsic::not_intrinsic) { 7131db9f3b2SDimitry Andric NewFn = Intrinsic::getDeclaration(F->getParent(), ID, 7141db9f3b2SDimitry Andric F->arg_begin()->getType()); 7151db9f3b2SDimitry Andric return true; 7161db9f3b2SDimitry Andric } 7171db9f3b2SDimitry Andric 7181db9f3b2SDimitry Andric if (Name.consume_front("vst")) { 7191db9f3b2SDimitry Andric // 'arm.neon.vst*'. 7201db9f3b2SDimitry Andric static const Regex vstRegex("^([1234]|[234]lane)\\.v[a-z0-9]*$"); 7211db9f3b2SDimitry Andric SmallVector<StringRef, 2> Groups; 7221db9f3b2SDimitry Andric if (vstRegex.match(Name, &Groups)) { 7231db9f3b2SDimitry Andric static const Intrinsic::ID StoreInts[] = { 7241db9f3b2SDimitry Andric Intrinsic::arm_neon_vst1, Intrinsic::arm_neon_vst2, 7251db9f3b2SDimitry Andric Intrinsic::arm_neon_vst3, Intrinsic::arm_neon_vst4}; 7261db9f3b2SDimitry Andric 7271db9f3b2SDimitry Andric static const Intrinsic::ID StoreLaneInts[] = { 7281db9f3b2SDimitry Andric Intrinsic::arm_neon_vst2lane, Intrinsic::arm_neon_vst3lane, 7291db9f3b2SDimitry Andric Intrinsic::arm_neon_vst4lane}; 7301db9f3b2SDimitry Andric 7311db9f3b2SDimitry Andric auto fArgs = F->getFunctionType()->params(); 7321db9f3b2SDimitry Andric Type *Tys[] = {fArgs[0], fArgs[1]}; 7331db9f3b2SDimitry Andric if (Groups[1].size() == 1) 7341db9f3b2SDimitry Andric NewFn = Intrinsic::getDeclaration(F->getParent(), 7351db9f3b2SDimitry Andric StoreInts[fArgs.size() - 3], Tys); 7361db9f3b2SDimitry Andric else 7371db9f3b2SDimitry Andric NewFn = Intrinsic::getDeclaration( 7381db9f3b2SDimitry Andric F->getParent(), StoreLaneInts[fArgs.size() - 5], Tys); 7391db9f3b2SDimitry Andric return true; 7401db9f3b2SDimitry Andric } 7411db9f3b2SDimitry Andric return false; // No other 'arm.neon.vst*'. 7421db9f3b2SDimitry Andric } 7431db9f3b2SDimitry Andric 7441db9f3b2SDimitry Andric return false; // No other 'arm.neon.*'. 7451db9f3b2SDimitry Andric } 7461db9f3b2SDimitry Andric 7471db9f3b2SDimitry Andric if (Name.consume_front("mve.")) { 7481db9f3b2SDimitry Andric // 'arm.mve.*'. 7491db9f3b2SDimitry Andric if (Name == "vctp64") { 7501db9f3b2SDimitry Andric if (cast<FixedVectorType>(F->getReturnType())->getNumElements() == 4) { 7511db9f3b2SDimitry Andric // A vctp64 returning a v4i1 is converted to return a v2i1. Rename 7521db9f3b2SDimitry Andric // the function and deal with it below in UpgradeIntrinsicCall. 7531db9f3b2SDimitry Andric rename(F); 7541db9f3b2SDimitry Andric return true; 7551db9f3b2SDimitry Andric } 7561db9f3b2SDimitry Andric return false; // Not 'arm.mve.vctp64'. 7571db9f3b2SDimitry Andric } 7581db9f3b2SDimitry Andric 7591db9f3b2SDimitry Andric // These too are changed to accept a v2i1 instead of the old v4i1. 7601db9f3b2SDimitry Andric if (Name.consume_back(".v4i1")) { 7611db9f3b2SDimitry Andric // 'arm.mve.*.v4i1'. 7621db9f3b2SDimitry Andric if (Name.consume_back(".predicated.v2i64.v4i32")) 7631db9f3b2SDimitry Andric // 'arm.mve.*.predicated.v2i64.v4i32.v4i1' 7641db9f3b2SDimitry Andric return Name == "mull.int" || Name == "vqdmull"; 7651db9f3b2SDimitry Andric 7661db9f3b2SDimitry Andric if (Name.consume_back(".v2i64")) { 7671db9f3b2SDimitry Andric // 'arm.mve.*.v2i64.v4i1' 7681db9f3b2SDimitry Andric bool IsGather = Name.consume_front("vldr.gather."); 7691db9f3b2SDimitry Andric if (IsGather || Name.consume_front("vstr.scatter.")) { 7701db9f3b2SDimitry Andric if (Name.consume_front("base.")) { 7711db9f3b2SDimitry Andric // Optional 'wb.' prefix. 7721db9f3b2SDimitry Andric Name.consume_front("wb."); 7731db9f3b2SDimitry Andric // 'arm.mve.(vldr.gather|vstr.scatter).base.(wb.)? 7741db9f3b2SDimitry Andric // predicated.v2i64.v2i64.v4i1'. 7751db9f3b2SDimitry Andric return Name == "predicated.v2i64"; 7761db9f3b2SDimitry Andric } 7771db9f3b2SDimitry Andric 7781db9f3b2SDimitry Andric if (Name.consume_front("offset.predicated.")) 7791db9f3b2SDimitry Andric return Name == (IsGather ? "v2i64.p0i64" : "p0i64.v2i64") || 7801db9f3b2SDimitry Andric Name == (IsGather ? "v2i64.p0" : "p0.v2i64"); 7811db9f3b2SDimitry Andric 7821db9f3b2SDimitry Andric // No other 'arm.mve.(vldr.gather|vstr.scatter).*.v2i64.v4i1'. 7831db9f3b2SDimitry Andric return false; 7841db9f3b2SDimitry Andric } 7851db9f3b2SDimitry Andric 7861db9f3b2SDimitry Andric return false; // No other 'arm.mve.*.v2i64.v4i1'. 7871db9f3b2SDimitry Andric } 7881db9f3b2SDimitry Andric return false; // No other 'arm.mve.*.v4i1'. 7891db9f3b2SDimitry Andric } 7901db9f3b2SDimitry Andric return false; // No other 'arm.mve.*'. 7911db9f3b2SDimitry Andric } 7921db9f3b2SDimitry Andric 7931db9f3b2SDimitry Andric if (Name.consume_front("cde.vcx")) { 7941db9f3b2SDimitry Andric // 'arm.cde.vcx*'. 7951db9f3b2SDimitry Andric if (Name.consume_back(".predicated.v2i64.v4i1")) 7961db9f3b2SDimitry Andric // 'arm.cde.vcx*.predicated.v2i64.v4i1'. 7971db9f3b2SDimitry Andric return Name == "1q" || Name == "1qa" || Name == "2q" || Name == "2qa" || 7981db9f3b2SDimitry Andric Name == "3q" || Name == "3qa"; 7991db9f3b2SDimitry Andric 8001db9f3b2SDimitry Andric return false; // No other 'arm.cde.vcx*'. 8011db9f3b2SDimitry Andric } 8021db9f3b2SDimitry Andric } else { 8031db9f3b2SDimitry Andric // 'aarch64.*'. 8041db9f3b2SDimitry Andric if (Neon) { 8051db9f3b2SDimitry Andric // 'aarch64.neon.*'. 8061db9f3b2SDimitry Andric Intrinsic::ID ID = StringSwitch<Intrinsic::ID>(Name) 8071db9f3b2SDimitry Andric .StartsWith("frintn", Intrinsic::roundeven) 8081db9f3b2SDimitry Andric .StartsWith("rbit", Intrinsic::bitreverse) 8091db9f3b2SDimitry Andric .Default(Intrinsic::not_intrinsic); 8101db9f3b2SDimitry Andric if (ID != Intrinsic::not_intrinsic) { 8111db9f3b2SDimitry Andric NewFn = Intrinsic::getDeclaration(F->getParent(), ID, 8121db9f3b2SDimitry Andric F->arg_begin()->getType()); 8131db9f3b2SDimitry Andric return true; 8141db9f3b2SDimitry Andric } 8151db9f3b2SDimitry Andric 8161db9f3b2SDimitry Andric if (Name.starts_with("addp")) { 8171db9f3b2SDimitry Andric // 'aarch64.neon.addp*'. 8181db9f3b2SDimitry Andric if (F->arg_size() != 2) 8191db9f3b2SDimitry Andric return false; // Invalid IR. 8201db9f3b2SDimitry Andric VectorType *Ty = dyn_cast<VectorType>(F->getReturnType()); 8211db9f3b2SDimitry Andric if (Ty && Ty->getElementType()->isFloatingPointTy()) { 8221db9f3b2SDimitry Andric NewFn = Intrinsic::getDeclaration(F->getParent(), 8231db9f3b2SDimitry Andric Intrinsic::aarch64_neon_faddp, Ty); 8241db9f3b2SDimitry Andric return true; 8251db9f3b2SDimitry Andric } 8261db9f3b2SDimitry Andric } 8271db9f3b2SDimitry Andric return false; // No other 'aarch64.neon.*'. 8281db9f3b2SDimitry Andric } 8291db9f3b2SDimitry Andric if (Name.consume_front("sve.")) { 8301db9f3b2SDimitry Andric // 'aarch64.sve.*'. 8311db9f3b2SDimitry Andric if (Name.consume_front("bf")) { 8321db9f3b2SDimitry Andric if (Name.consume_back(".lane")) { 8331db9f3b2SDimitry Andric // 'aarch64.sve.bf*.lane'. 8341db9f3b2SDimitry Andric Intrinsic::ID ID = 8351db9f3b2SDimitry Andric StringSwitch<Intrinsic::ID>(Name) 8361db9f3b2SDimitry Andric .Case("dot", Intrinsic::aarch64_sve_bfdot_lane_v2) 8371db9f3b2SDimitry Andric .Case("mlalb", Intrinsic::aarch64_sve_bfmlalb_lane_v2) 8381db9f3b2SDimitry Andric .Case("mlalt", Intrinsic::aarch64_sve_bfmlalt_lane_v2) 8391db9f3b2SDimitry Andric .Default(Intrinsic::not_intrinsic); 8401db9f3b2SDimitry Andric if (ID != Intrinsic::not_intrinsic) { 8411db9f3b2SDimitry Andric NewFn = Intrinsic::getDeclaration(F->getParent(), ID); 8421db9f3b2SDimitry Andric return true; 8431db9f3b2SDimitry Andric } 8441db9f3b2SDimitry Andric return false; // No other 'aarch64.sve.bf*.lane'. 8451db9f3b2SDimitry Andric } 8461db9f3b2SDimitry Andric return false; // No other 'aarch64.sve.bf*'. 8471db9f3b2SDimitry Andric } 8481db9f3b2SDimitry Andric 849*0fca6ea1SDimitry Andric if (Name.consume_front("addqv")) { 850*0fca6ea1SDimitry Andric // 'aarch64.sve.addqv'. 851*0fca6ea1SDimitry Andric if (!F->getReturnType()->isFPOrFPVectorTy()) 852*0fca6ea1SDimitry Andric return false; 853*0fca6ea1SDimitry Andric 854*0fca6ea1SDimitry Andric auto Args = F->getFunctionType()->params(); 855*0fca6ea1SDimitry Andric Type *Tys[] = {F->getReturnType(), Args[1]}; 856*0fca6ea1SDimitry Andric NewFn = Intrinsic::getDeclaration(F->getParent(), 857*0fca6ea1SDimitry Andric Intrinsic::aarch64_sve_faddqv, Tys); 858*0fca6ea1SDimitry Andric return true; 859*0fca6ea1SDimitry Andric } 860*0fca6ea1SDimitry Andric 8611db9f3b2SDimitry Andric if (Name.consume_front("ld")) { 8621db9f3b2SDimitry Andric // 'aarch64.sve.ld*'. 8631db9f3b2SDimitry Andric static const Regex LdRegex("^[234](.nxv[a-z0-9]+|$)"); 8641db9f3b2SDimitry Andric if (LdRegex.match(Name)) { 8651db9f3b2SDimitry Andric Type *ScalarTy = 866*0fca6ea1SDimitry Andric cast<VectorType>(F->getReturnType())->getElementType(); 867*0fca6ea1SDimitry Andric ElementCount EC = 868*0fca6ea1SDimitry Andric cast<VectorType>(F->arg_begin()->getType())->getElementCount(); 8691db9f3b2SDimitry Andric Type *Ty = VectorType::get(ScalarTy, EC); 8701db9f3b2SDimitry Andric static const Intrinsic::ID LoadIDs[] = { 8711db9f3b2SDimitry Andric Intrinsic::aarch64_sve_ld2_sret, 8721db9f3b2SDimitry Andric Intrinsic::aarch64_sve_ld3_sret, 8731db9f3b2SDimitry Andric Intrinsic::aarch64_sve_ld4_sret, 8741db9f3b2SDimitry Andric }; 8751db9f3b2SDimitry Andric NewFn = Intrinsic::getDeclaration(F->getParent(), 8761db9f3b2SDimitry Andric LoadIDs[Name[0] - '2'], Ty); 8771db9f3b2SDimitry Andric return true; 8781db9f3b2SDimitry Andric } 8791db9f3b2SDimitry Andric return false; // No other 'aarch64.sve.ld*'. 8801db9f3b2SDimitry Andric } 8811db9f3b2SDimitry Andric 8821db9f3b2SDimitry Andric if (Name.consume_front("tuple.")) { 8831db9f3b2SDimitry Andric // 'aarch64.sve.tuple.*'. 8841db9f3b2SDimitry Andric if (Name.starts_with("get")) { 8851db9f3b2SDimitry Andric // 'aarch64.sve.tuple.get*'. 8861db9f3b2SDimitry Andric Type *Tys[] = {F->getReturnType(), F->arg_begin()->getType()}; 8871db9f3b2SDimitry Andric NewFn = Intrinsic::getDeclaration(F->getParent(), 8881db9f3b2SDimitry Andric Intrinsic::vector_extract, Tys); 8891db9f3b2SDimitry Andric return true; 8901db9f3b2SDimitry Andric } 8911db9f3b2SDimitry Andric 8921db9f3b2SDimitry Andric if (Name.starts_with("set")) { 8931db9f3b2SDimitry Andric // 'aarch64.sve.tuple.set*'. 8941db9f3b2SDimitry Andric auto Args = F->getFunctionType()->params(); 8951db9f3b2SDimitry Andric Type *Tys[] = {Args[0], Args[2], Args[1]}; 8961db9f3b2SDimitry Andric NewFn = Intrinsic::getDeclaration(F->getParent(), 8971db9f3b2SDimitry Andric Intrinsic::vector_insert, Tys); 8981db9f3b2SDimitry Andric return true; 8991db9f3b2SDimitry Andric } 9001db9f3b2SDimitry Andric 9011db9f3b2SDimitry Andric static const Regex CreateTupleRegex("^create[234](.nxv[a-z0-9]+|$)"); 9021db9f3b2SDimitry Andric if (CreateTupleRegex.match(Name)) { 9031db9f3b2SDimitry Andric // 'aarch64.sve.tuple.create*'. 9041db9f3b2SDimitry Andric auto Args = F->getFunctionType()->params(); 9051db9f3b2SDimitry Andric Type *Tys[] = {F->getReturnType(), Args[1]}; 9061db9f3b2SDimitry Andric NewFn = Intrinsic::getDeclaration(F->getParent(), 9071db9f3b2SDimitry Andric Intrinsic::vector_insert, Tys); 9081db9f3b2SDimitry Andric return true; 9091db9f3b2SDimitry Andric } 9101db9f3b2SDimitry Andric return false; // No other 'aarch64.sve.tuple.*'. 9111db9f3b2SDimitry Andric } 9121db9f3b2SDimitry Andric return false; // No other 'aarch64.sve.*'. 9131db9f3b2SDimitry Andric } 9141db9f3b2SDimitry Andric } 9151db9f3b2SDimitry Andric return false; // No other 'arm.*', 'aarch64.*'. 9161db9f3b2SDimitry Andric } 9171db9f3b2SDimitry Andric 9187a6dacacSDimitry Andric static Intrinsic::ID shouldUpgradeNVPTXBF16Intrinsic(StringRef Name) { 9195f757f3fSDimitry Andric if (Name.consume_front("abs.")) 92006c3fb27SDimitry Andric return StringSwitch<Intrinsic::ID>(Name) 9215f757f3fSDimitry Andric .Case("bf16", Intrinsic::nvvm_abs_bf16) 9225f757f3fSDimitry Andric .Case("bf16x2", Intrinsic::nvvm_abs_bf16x2) 92306c3fb27SDimitry Andric .Default(Intrinsic::not_intrinsic); 9245f757f3fSDimitry Andric 9255f757f3fSDimitry Andric if (Name.consume_front("fma.rn.")) 9265f757f3fSDimitry Andric return StringSwitch<Intrinsic::ID>(Name) 9275f757f3fSDimitry Andric .Case("bf16", Intrinsic::nvvm_fma_rn_bf16) 9285f757f3fSDimitry Andric .Case("bf16x2", Intrinsic::nvvm_fma_rn_bf16x2) 9295f757f3fSDimitry Andric .Case("ftz.bf16", Intrinsic::nvvm_fma_rn_ftz_bf16) 9305f757f3fSDimitry Andric .Case("ftz.bf16x2", Intrinsic::nvvm_fma_rn_ftz_bf16x2) 9315f757f3fSDimitry Andric .Case("ftz.relu.bf16", Intrinsic::nvvm_fma_rn_ftz_relu_bf16) 9325f757f3fSDimitry Andric .Case("ftz.relu.bf16x2", Intrinsic::nvvm_fma_rn_ftz_relu_bf16x2) 9335f757f3fSDimitry Andric .Case("ftz.sat.bf16", Intrinsic::nvvm_fma_rn_ftz_sat_bf16) 9345f757f3fSDimitry Andric .Case("ftz.sat.bf16x2", Intrinsic::nvvm_fma_rn_ftz_sat_bf16x2) 9355f757f3fSDimitry Andric .Case("relu.bf16", Intrinsic::nvvm_fma_rn_relu_bf16) 9365f757f3fSDimitry Andric .Case("relu.bf16x2", Intrinsic::nvvm_fma_rn_relu_bf16x2) 9375f757f3fSDimitry Andric .Case("sat.bf16", Intrinsic::nvvm_fma_rn_sat_bf16) 9385f757f3fSDimitry Andric .Case("sat.bf16x2", Intrinsic::nvvm_fma_rn_sat_bf16x2) 9395f757f3fSDimitry Andric .Default(Intrinsic::not_intrinsic); 9405f757f3fSDimitry Andric 9415f757f3fSDimitry Andric if (Name.consume_front("fmax.")) 9425f757f3fSDimitry Andric return StringSwitch<Intrinsic::ID>(Name) 9435f757f3fSDimitry Andric .Case("bf16", Intrinsic::nvvm_fmax_bf16) 9445f757f3fSDimitry Andric .Case("bf16x2", Intrinsic::nvvm_fmax_bf16x2) 9455f757f3fSDimitry Andric .Case("ftz.bf16", Intrinsic::nvvm_fmax_ftz_bf16) 9465f757f3fSDimitry Andric .Case("ftz.bf16x2", Intrinsic::nvvm_fmax_ftz_bf16x2) 9475f757f3fSDimitry Andric .Case("ftz.nan.bf16", Intrinsic::nvvm_fmax_ftz_nan_bf16) 9485f757f3fSDimitry Andric .Case("ftz.nan.bf16x2", Intrinsic::nvvm_fmax_ftz_nan_bf16x2) 9495f757f3fSDimitry Andric .Case("ftz.nan.xorsign.abs.bf16", 9505f757f3fSDimitry Andric Intrinsic::nvvm_fmax_ftz_nan_xorsign_abs_bf16) 9515f757f3fSDimitry Andric .Case("ftz.nan.xorsign.abs.bf16x2", 9525f757f3fSDimitry Andric Intrinsic::nvvm_fmax_ftz_nan_xorsign_abs_bf16x2) 9535f757f3fSDimitry Andric .Case("ftz.xorsign.abs.bf16", Intrinsic::nvvm_fmax_ftz_xorsign_abs_bf16) 9545f757f3fSDimitry Andric .Case("ftz.xorsign.abs.bf16x2", 9555f757f3fSDimitry Andric Intrinsic::nvvm_fmax_ftz_xorsign_abs_bf16x2) 9565f757f3fSDimitry Andric .Case("nan.bf16", Intrinsic::nvvm_fmax_nan_bf16) 9575f757f3fSDimitry Andric .Case("nan.bf16x2", Intrinsic::nvvm_fmax_nan_bf16x2) 9585f757f3fSDimitry Andric .Case("nan.xorsign.abs.bf16", Intrinsic::nvvm_fmax_nan_xorsign_abs_bf16) 9595f757f3fSDimitry Andric .Case("nan.xorsign.abs.bf16x2", 9605f757f3fSDimitry Andric Intrinsic::nvvm_fmax_nan_xorsign_abs_bf16x2) 9615f757f3fSDimitry Andric .Case("xorsign.abs.bf16", Intrinsic::nvvm_fmax_xorsign_abs_bf16) 9625f757f3fSDimitry Andric .Case("xorsign.abs.bf16x2", Intrinsic::nvvm_fmax_xorsign_abs_bf16x2) 9635f757f3fSDimitry Andric .Default(Intrinsic::not_intrinsic); 9645f757f3fSDimitry Andric 9655f757f3fSDimitry Andric if (Name.consume_front("fmin.")) 9665f757f3fSDimitry Andric return StringSwitch<Intrinsic::ID>(Name) 9675f757f3fSDimitry Andric .Case("bf16", Intrinsic::nvvm_fmin_bf16) 9685f757f3fSDimitry Andric .Case("bf16x2", Intrinsic::nvvm_fmin_bf16x2) 9695f757f3fSDimitry Andric .Case("ftz.bf16", Intrinsic::nvvm_fmin_ftz_bf16) 9705f757f3fSDimitry Andric .Case("ftz.bf16x2", Intrinsic::nvvm_fmin_ftz_bf16x2) 9715f757f3fSDimitry Andric .Case("ftz.nan.bf16", Intrinsic::nvvm_fmin_ftz_nan_bf16) 9725f757f3fSDimitry Andric .Case("ftz.nan.bf16x2", Intrinsic::nvvm_fmin_ftz_nan_bf16x2) 9735f757f3fSDimitry Andric .Case("ftz.nan.xorsign.abs.bf16", 9745f757f3fSDimitry Andric Intrinsic::nvvm_fmin_ftz_nan_xorsign_abs_bf16) 9755f757f3fSDimitry Andric .Case("ftz.nan.xorsign.abs.bf16x2", 9765f757f3fSDimitry Andric Intrinsic::nvvm_fmin_ftz_nan_xorsign_abs_bf16x2) 9775f757f3fSDimitry Andric .Case("ftz.xorsign.abs.bf16", Intrinsic::nvvm_fmin_ftz_xorsign_abs_bf16) 9785f757f3fSDimitry Andric .Case("ftz.xorsign.abs.bf16x2", 9795f757f3fSDimitry Andric Intrinsic::nvvm_fmin_ftz_xorsign_abs_bf16x2) 9805f757f3fSDimitry Andric .Case("nan.bf16", Intrinsic::nvvm_fmin_nan_bf16) 9815f757f3fSDimitry Andric .Case("nan.bf16x2", Intrinsic::nvvm_fmin_nan_bf16x2) 9825f757f3fSDimitry Andric .Case("nan.xorsign.abs.bf16", Intrinsic::nvvm_fmin_nan_xorsign_abs_bf16) 9835f757f3fSDimitry Andric .Case("nan.xorsign.abs.bf16x2", 9845f757f3fSDimitry Andric Intrinsic::nvvm_fmin_nan_xorsign_abs_bf16x2) 9855f757f3fSDimitry Andric .Case("xorsign.abs.bf16", Intrinsic::nvvm_fmin_xorsign_abs_bf16) 9865f757f3fSDimitry Andric .Case("xorsign.abs.bf16x2", Intrinsic::nvvm_fmin_xorsign_abs_bf16x2) 9875f757f3fSDimitry Andric .Default(Intrinsic::not_intrinsic); 9885f757f3fSDimitry Andric 9895f757f3fSDimitry Andric if (Name.consume_front("neg.")) 9905f757f3fSDimitry Andric return StringSwitch<Intrinsic::ID>(Name) 9915f757f3fSDimitry Andric .Case("bf16", Intrinsic::nvvm_neg_bf16) 9925f757f3fSDimitry Andric .Case("bf16x2", Intrinsic::nvvm_neg_bf16x2) 9935f757f3fSDimitry Andric .Default(Intrinsic::not_intrinsic); 9945f757f3fSDimitry Andric 9955f757f3fSDimitry Andric return Intrinsic::not_intrinsic; 99606c3fb27SDimitry Andric } 99706c3fb27SDimitry Andric 998*0fca6ea1SDimitry Andric static bool upgradeIntrinsicFunction1(Function *F, Function *&NewFn, 999*0fca6ea1SDimitry Andric bool CanUpgradeDebugIntrinsicsToRecords) { 10000b57cec5SDimitry Andric assert(F && "Illegal to upgrade a non-existent Function."); 10010b57cec5SDimitry Andric 10020b57cec5SDimitry Andric StringRef Name = F->getName(); 10035f757f3fSDimitry Andric 10045f757f3fSDimitry Andric // Quickly eliminate it, if it's not a candidate. 10055f757f3fSDimitry Andric if (!Name.consume_front("llvm.") || Name.empty()) 10060b57cec5SDimitry Andric return false; 10070b57cec5SDimitry Andric 10080b57cec5SDimitry Andric switch (Name[0]) { 10090b57cec5SDimitry Andric default: break; 10100b57cec5SDimitry Andric case 'a': { 10111db9f3b2SDimitry Andric bool IsArm = Name.consume_front("arm."); 10121db9f3b2SDimitry Andric if (IsArm || Name.consume_front("aarch64.")) { 10137a6dacacSDimitry Andric if (upgradeArmOrAarch64IntrinsicFunction(IsArm, F, Name, NewFn)) 10140b57cec5SDimitry Andric return true; 1015e8d8bef9SDimitry Andric break; 1016e8d8bef9SDimitry Andric } 1017e8d8bef9SDimitry Andric 10185f757f3fSDimitry Andric if (Name.consume_front("amdgcn.")) { 101906c3fb27SDimitry Andric if (Name == "alignbit") { 102004eeddc0SDimitry Andric // Target specific intrinsic became redundant 102104eeddc0SDimitry Andric NewFn = Intrinsic::getDeclaration(F->getParent(), Intrinsic::fshr, 102204eeddc0SDimitry Andric {F->getReturnType()}); 102304eeddc0SDimitry Andric return true; 102404eeddc0SDimitry Andric } 102504eeddc0SDimitry Andric 10265f757f3fSDimitry Andric if (Name.consume_front("atomic.")) { 10275f757f3fSDimitry Andric if (Name.starts_with("inc") || Name.starts_with("dec")) { 10285f757f3fSDimitry Andric // These were replaced with atomicrmw uinc_wrap and udec_wrap, so 10295f757f3fSDimitry Andric // there's no new declaration. 103006c3fb27SDimitry Andric NewFn = nullptr; 103106c3fb27SDimitry Andric return true; 10320b57cec5SDimitry Andric } 10335f757f3fSDimitry Andric break; // No other 'amdgcn.atomic.*' 10345f757f3fSDimitry Andric } 10355f757f3fSDimitry Andric 1036*0fca6ea1SDimitry Andric if (Name.starts_with("ds.fadd") || Name.starts_with("ds.fmin") || 1037*0fca6ea1SDimitry Andric Name.starts_with("ds.fmax")) { 1038*0fca6ea1SDimitry Andric // Replaced with atomicrmw fadd/fmin/fmax, so there's no new 1039*0fca6ea1SDimitry Andric // declaration. 1040*0fca6ea1SDimitry Andric NewFn = nullptr; 1041*0fca6ea1SDimitry Andric return true; 1042*0fca6ea1SDimitry Andric } 1043*0fca6ea1SDimitry Andric 10445f757f3fSDimitry Andric if (Name.starts_with("ldexp.")) { 10455f757f3fSDimitry Andric // Target specific intrinsic became redundant 10465f757f3fSDimitry Andric NewFn = Intrinsic::getDeclaration( 10475f757f3fSDimitry Andric F->getParent(), Intrinsic::ldexp, 10485f757f3fSDimitry Andric {F->getReturnType(), F->getArg(1)->getType()}); 10495f757f3fSDimitry Andric return true; 10505f757f3fSDimitry Andric } 10515f757f3fSDimitry Andric break; // No other 'amdgcn.*' 10525f757f3fSDimitry Andric } 10530b57cec5SDimitry Andric 105406c3fb27SDimitry Andric break; 105506c3fb27SDimitry Andric } 10560b57cec5SDimitry Andric case 'c': { 10575f757f3fSDimitry Andric if (F->arg_size() == 1) { 10585f757f3fSDimitry Andric Intrinsic::ID ID = StringSwitch<Intrinsic::ID>(Name) 10595f757f3fSDimitry Andric .StartsWith("ctlz.", Intrinsic::ctlz) 10605f757f3fSDimitry Andric .StartsWith("cttz.", Intrinsic::cttz) 10615f757f3fSDimitry Andric .Default(Intrinsic::not_intrinsic); 10625f757f3fSDimitry Andric if (ID != Intrinsic::not_intrinsic) { 10630b57cec5SDimitry Andric rename(F); 10645f757f3fSDimitry Andric NewFn = Intrinsic::getDeclaration(F->getParent(), ID, 10650b57cec5SDimitry Andric F->arg_begin()->getType()); 10660b57cec5SDimitry Andric return true; 10670b57cec5SDimitry Andric } 10685f757f3fSDimitry Andric } 10695f757f3fSDimitry Andric 1070*0fca6ea1SDimitry Andric if (F->arg_size() == 2 && Name == "coro.end") { 10710b57cec5SDimitry Andric rename(F); 10725f757f3fSDimitry Andric NewFn = Intrinsic::getDeclaration(F->getParent(), Intrinsic::coro_end); 10730b57cec5SDimitry Andric return true; 10740b57cec5SDimitry Andric } 10755f757f3fSDimitry Andric 10760b57cec5SDimitry Andric break; 10770b57cec5SDimitry Andric } 10785f757f3fSDimitry Andric case 'd': 10795f757f3fSDimitry Andric if (Name.consume_front("dbg.")) { 1080*0fca6ea1SDimitry Andric // Mark debug intrinsics for upgrade to new debug format. 1081*0fca6ea1SDimitry Andric if (CanUpgradeDebugIntrinsicsToRecords && 1082*0fca6ea1SDimitry Andric F->getParent()->IsNewDbgInfoFormat) { 1083*0fca6ea1SDimitry Andric if (Name == "addr" || Name == "value" || Name == "assign" || 1084*0fca6ea1SDimitry Andric Name == "declare" || Name == "label") { 1085*0fca6ea1SDimitry Andric // There's no function to replace these with. 1086*0fca6ea1SDimitry Andric NewFn = nullptr; 1087*0fca6ea1SDimitry Andric // But we do want these to get upgraded. 1088*0fca6ea1SDimitry Andric return true; 1089*0fca6ea1SDimitry Andric } 1090*0fca6ea1SDimitry Andric } 1091*0fca6ea1SDimitry Andric // Update llvm.dbg.addr intrinsics even in "new debug mode"; they'll get 1092*0fca6ea1SDimitry Andric // converted to DbgVariableRecords later. 10935f757f3fSDimitry Andric if (Name == "addr" || (Name == "value" && F->arg_size() == 4)) { 109406c3fb27SDimitry Andric rename(F); 109506c3fb27SDimitry Andric NewFn = Intrinsic::getDeclaration(F->getParent(), Intrinsic::dbg_value); 109606c3fb27SDimitry Andric return true; 109706c3fb27SDimitry Andric } 10985f757f3fSDimitry Andric break; // No other 'dbg.*'. 10990b57cec5SDimitry Andric } 11000b57cec5SDimitry Andric break; 11015f757f3fSDimitry Andric case 'e': 11025f757f3fSDimitry Andric if (Name.consume_front("experimental.vector.")) { 1103*0fca6ea1SDimitry Andric Intrinsic::ID ID = 1104*0fca6ea1SDimitry Andric StringSwitch<Intrinsic::ID>(Name) 11055f757f3fSDimitry Andric .StartsWith("extract.", Intrinsic::vector_extract) 11065f757f3fSDimitry Andric .StartsWith("insert.", Intrinsic::vector_insert) 1107*0fca6ea1SDimitry Andric .StartsWith("splice.", Intrinsic::vector_splice) 1108*0fca6ea1SDimitry Andric .StartsWith("reverse.", Intrinsic::vector_reverse) 1109*0fca6ea1SDimitry Andric .StartsWith("interleave2.", Intrinsic::vector_interleave2) 1110*0fca6ea1SDimitry Andric .StartsWith("deinterleave2.", Intrinsic::vector_deinterleave2) 11115f757f3fSDimitry Andric .Default(Intrinsic::not_intrinsic); 11125f757f3fSDimitry Andric if (ID != Intrinsic::not_intrinsic) { 11135f757f3fSDimitry Andric const auto *FT = F->getFunctionType(); 11145f757f3fSDimitry Andric SmallVector<Type *, 2> Tys; 1115*0fca6ea1SDimitry Andric if (ID == Intrinsic::vector_extract || 1116*0fca6ea1SDimitry Andric ID == Intrinsic::vector_interleave2) 11175f757f3fSDimitry Andric // Extracting overloads the return type. 11185f757f3fSDimitry Andric Tys.push_back(FT->getReturnType()); 1119*0fca6ea1SDimitry Andric if (ID != Intrinsic::vector_interleave2) 11205f757f3fSDimitry Andric Tys.push_back(FT->getParamType(0)); 11215f757f3fSDimitry Andric if (ID == Intrinsic::vector_insert) 11225f757f3fSDimitry Andric // Inserting overloads the inserted type. 11235f757f3fSDimitry Andric Tys.push_back(FT->getParamType(1)); 112481ad6265SDimitry Andric rename(F); 11255f757f3fSDimitry Andric NewFn = Intrinsic::getDeclaration(F->getParent(), ID, Tys); 112681ad6265SDimitry Andric return true; 112781ad6265SDimitry Andric } 112881ad6265SDimitry Andric 11295f757f3fSDimitry Andric if (Name.consume_front("reduce.")) { 11300b57cec5SDimitry Andric SmallVector<StringRef, 2> Groups; 11315f757f3fSDimitry Andric static const Regex R("^([a-z]+)\\.[a-z][0-9]+"); 11325f757f3fSDimitry Andric if (R.match(Name, &Groups)) 1133e8d8bef9SDimitry Andric ID = StringSwitch<Intrinsic::ID>(Groups[1]) 1134e8d8bef9SDimitry Andric .Case("add", Intrinsic::vector_reduce_add) 1135e8d8bef9SDimitry Andric .Case("mul", Intrinsic::vector_reduce_mul) 1136e8d8bef9SDimitry Andric .Case("and", Intrinsic::vector_reduce_and) 1137e8d8bef9SDimitry Andric .Case("or", Intrinsic::vector_reduce_or) 1138e8d8bef9SDimitry Andric .Case("xor", Intrinsic::vector_reduce_xor) 1139e8d8bef9SDimitry Andric .Case("smax", Intrinsic::vector_reduce_smax) 1140e8d8bef9SDimitry Andric .Case("smin", Intrinsic::vector_reduce_smin) 1141e8d8bef9SDimitry Andric .Case("umax", Intrinsic::vector_reduce_umax) 1142e8d8bef9SDimitry Andric .Case("umin", Intrinsic::vector_reduce_umin) 1143e8d8bef9SDimitry Andric .Case("fmax", Intrinsic::vector_reduce_fmax) 1144e8d8bef9SDimitry Andric .Case("fmin", Intrinsic::vector_reduce_fmin) 1145e8d8bef9SDimitry Andric .Default(Intrinsic::not_intrinsic); 11465f757f3fSDimitry Andric 11475f757f3fSDimitry Andric bool V2 = false; 11485f757f3fSDimitry Andric if (ID == Intrinsic::not_intrinsic) { 11495f757f3fSDimitry Andric static const Regex R2("^v2\\.([a-z]+)\\.[fi][0-9]+"); 1150e8d8bef9SDimitry Andric Groups.clear(); 11515f757f3fSDimitry Andric V2 = true; 11525f757f3fSDimitry Andric if (R2.match(Name, &Groups)) 11535f757f3fSDimitry Andric ID = StringSwitch<Intrinsic::ID>(Groups[1]) 11545f757f3fSDimitry Andric .Case("fadd", Intrinsic::vector_reduce_fadd) 11555f757f3fSDimitry Andric .Case("fmul", Intrinsic::vector_reduce_fmul) 11565f757f3fSDimitry Andric .Default(Intrinsic::not_intrinsic); 11575f757f3fSDimitry Andric } 1158e8d8bef9SDimitry Andric if (ID != Intrinsic::not_intrinsic) { 1159e8d8bef9SDimitry Andric rename(F); 1160e8d8bef9SDimitry Andric auto Args = F->getFunctionType()->params(); 11615f757f3fSDimitry Andric NewFn = 11625f757f3fSDimitry Andric Intrinsic::getDeclaration(F->getParent(), ID, {Args[V2 ? 1 : 0]}); 11630b57cec5SDimitry Andric return true; 11640b57cec5SDimitry Andric } 11655f757f3fSDimitry Andric break; // No other 'expermental.vector.reduce.*'. 11660b57cec5SDimitry Andric } 11675f757f3fSDimitry Andric break; // No other 'experimental.vector.*'. 11680b57cec5SDimitry Andric } 11695f757f3fSDimitry Andric break; // No other 'e*'. 1170bdd1243dSDimitry Andric case 'f': 11715f757f3fSDimitry Andric if (Name.starts_with("flt.rounds")) { 1172bdd1243dSDimitry Andric rename(F); 1173bdd1243dSDimitry Andric NewFn = Intrinsic::getDeclaration(F->getParent(), Intrinsic::get_rounding); 1174bdd1243dSDimitry Andric return true; 1175bdd1243dSDimitry Andric } 1176bdd1243dSDimitry Andric break; 11770b57cec5SDimitry Andric case 'i': 11785f757f3fSDimitry Andric if (Name.starts_with("invariant.group.barrier")) { 11790b57cec5SDimitry Andric // Rename invariant.group.barrier to launder.invariant.group 11800b57cec5SDimitry Andric auto Args = F->getFunctionType()->params(); 11810b57cec5SDimitry Andric Type* ObjectPtr[1] = {Args[0]}; 11820b57cec5SDimitry Andric rename(F); 11830b57cec5SDimitry Andric NewFn = Intrinsic::getDeclaration(F->getParent(), 11840b57cec5SDimitry Andric Intrinsic::launder_invariant_group, ObjectPtr); 11850b57cec5SDimitry Andric return true; 11860b57cec5SDimitry Andric } 11870b57cec5SDimitry Andric break; 11880b57cec5SDimitry Andric case 'm': { 11890b57cec5SDimitry Andric // Updating the memory intrinsics (memcpy/memmove/memset) that have an 11900b57cec5SDimitry Andric // alignment parameter to embedding the alignment as an attribute of 11910b57cec5SDimitry Andric // the pointer args. 11925f757f3fSDimitry Andric if (unsigned ID = StringSwitch<unsigned>(Name) 11935f757f3fSDimitry Andric .StartsWith("memcpy.", Intrinsic::memcpy) 11945f757f3fSDimitry Andric .StartsWith("memmove.", Intrinsic::memmove) 11955f757f3fSDimitry Andric .Default(0)) { 11965f757f3fSDimitry Andric if (F->arg_size() == 5) { 11970b57cec5SDimitry Andric rename(F); 11980b57cec5SDimitry Andric // Get the types of dest, src, and len 11995f757f3fSDimitry Andric ArrayRef<Type *> ParamTypes = 12005f757f3fSDimitry Andric F->getFunctionType()->params().slice(0, 3); 12015f757f3fSDimitry Andric NewFn = Intrinsic::getDeclaration(F->getParent(), ID, ParamTypes); 12020b57cec5SDimitry Andric return true; 12030b57cec5SDimitry Andric } 12040b57cec5SDimitry Andric } 12055f757f3fSDimitry Andric if (Name.starts_with("memset.") && F->arg_size() == 5) { 12060b57cec5SDimitry Andric rename(F); 12070b57cec5SDimitry Andric // Get the types of dest, and len 12080b57cec5SDimitry Andric const auto *FT = F->getFunctionType(); 12090b57cec5SDimitry Andric Type *ParamTypes[2] = { 12100b57cec5SDimitry Andric FT->getParamType(0), // Dest 12110b57cec5SDimitry Andric FT->getParamType(2) // len 12120b57cec5SDimitry Andric }; 12130b57cec5SDimitry Andric NewFn = Intrinsic::getDeclaration(F->getParent(), Intrinsic::memset, 12140b57cec5SDimitry Andric ParamTypes); 12150b57cec5SDimitry Andric return true; 12160b57cec5SDimitry Andric } 12170b57cec5SDimitry Andric break; 12180b57cec5SDimitry Andric } 12190b57cec5SDimitry Andric case 'n': { 12205f757f3fSDimitry Andric if (Name.consume_front("nvvm.")) { 12215f757f3fSDimitry Andric // Check for nvvm intrinsics corresponding exactly to an LLVM intrinsic. 12225f757f3fSDimitry Andric if (F->arg_size() == 1) { 12235f757f3fSDimitry Andric Intrinsic::ID IID = 12245f757f3fSDimitry Andric StringSwitch<Intrinsic::ID>(Name) 12250b57cec5SDimitry Andric .Cases("brev32", "brev64", Intrinsic::bitreverse) 12260b57cec5SDimitry Andric .Case("clz.i", Intrinsic::ctlz) 12270b57cec5SDimitry Andric .Case("popc.i", Intrinsic::ctpop) 12280b57cec5SDimitry Andric .Default(Intrinsic::not_intrinsic); 12295f757f3fSDimitry Andric if (IID != Intrinsic::not_intrinsic) { 12300b57cec5SDimitry Andric NewFn = Intrinsic::getDeclaration(F->getParent(), IID, 12310b57cec5SDimitry Andric {F->getReturnType()}); 12320b57cec5SDimitry Andric return true; 12330b57cec5SDimitry Andric } 12345f757f3fSDimitry Andric } 12355f757f3fSDimitry Andric 12365f757f3fSDimitry Andric // Check for nvvm intrinsics that need a return type adjustment. 12375f757f3fSDimitry Andric if (!F->getReturnType()->getScalarType()->isBFloatTy()) { 12387a6dacacSDimitry Andric Intrinsic::ID IID = shouldUpgradeNVPTXBF16Intrinsic(Name); 12395f757f3fSDimitry Andric if (IID != Intrinsic::not_intrinsic) { 124006c3fb27SDimitry Andric NewFn = nullptr; 124106c3fb27SDimitry Andric return true; 124206c3fb27SDimitry Andric } 12435f757f3fSDimitry Andric } 12445f757f3fSDimitry Andric 12450b57cec5SDimitry Andric // The following nvvm intrinsics correspond exactly to an LLVM idiom, but 12460b57cec5SDimitry Andric // not to an intrinsic alone. We expand them in UpgradeIntrinsicCall. 12470b57cec5SDimitry Andric // 12480b57cec5SDimitry Andric // TODO: We could add lohi.i2d. 12495f757f3fSDimitry Andric bool Expand = false; 12505f757f3fSDimitry Andric if (Name.consume_front("abs.")) 12515f757f3fSDimitry Andric // nvvm.abs.{i,ii} 12525f757f3fSDimitry Andric Expand = Name == "i" || Name == "ll"; 12535f757f3fSDimitry Andric else if (Name == "clz.ll" || Name == "popc.ll" || Name == "h2f") 12545f757f3fSDimitry Andric Expand = true; 12555f757f3fSDimitry Andric else if (Name.consume_front("max.") || Name.consume_front("min.")) 12565f757f3fSDimitry Andric // nvvm.{min,max}.{i,ii,ui,ull} 12577a6dacacSDimitry Andric Expand = Name == "s" || Name == "i" || Name == "ll" || Name == "us" || 12587a6dacacSDimitry Andric Name == "ui" || Name == "ull"; 12595f757f3fSDimitry Andric else if (Name.consume_front("atomic.load.add.")) 12605f757f3fSDimitry Andric // nvvm.atomic.load.add.{f32.p,f64.p} 12615f757f3fSDimitry Andric Expand = Name.starts_with("f32.p") || Name.starts_with("f64.p"); 12625f757f3fSDimitry Andric else 12635f757f3fSDimitry Andric Expand = false; 12645f757f3fSDimitry Andric 12650b57cec5SDimitry Andric if (Expand) { 12660b57cec5SDimitry Andric NewFn = nullptr; 12670b57cec5SDimitry Andric return true; 12680b57cec5SDimitry Andric } 12695f757f3fSDimitry Andric break; // No other 'nvvm.*'. 12700b57cec5SDimitry Andric } 12710b57cec5SDimitry Andric break; 12720b57cec5SDimitry Andric } 12730b57cec5SDimitry Andric case 'o': 12740b57cec5SDimitry Andric // We only need to change the name to match the mangling including the 12750b57cec5SDimitry Andric // address space. 12765f757f3fSDimitry Andric if (Name.starts_with("objectsize.")) { 12770b57cec5SDimitry Andric Type *Tys[2] = { F->getReturnType(), F->arg_begin()->getType() }; 12780b57cec5SDimitry Andric if (F->arg_size() == 2 || F->arg_size() == 3 || 1279fe6060f1SDimitry Andric F->getName() != 1280fe6060f1SDimitry Andric Intrinsic::getName(Intrinsic::objectsize, Tys, F->getParent())) { 12810b57cec5SDimitry Andric rename(F); 12820b57cec5SDimitry Andric NewFn = Intrinsic::getDeclaration(F->getParent(), Intrinsic::objectsize, 12830b57cec5SDimitry Andric Tys); 12840b57cec5SDimitry Andric return true; 12850b57cec5SDimitry Andric } 12860b57cec5SDimitry Andric } 12870b57cec5SDimitry Andric break; 12880b57cec5SDimitry Andric 12898bcb0991SDimitry Andric case 'p': 12905f757f3fSDimitry Andric if (Name.starts_with("ptr.annotation.") && F->arg_size() == 4) { 1291d409305fSDimitry Andric rename(F); 1292bdd1243dSDimitry Andric NewFn = Intrinsic::getDeclaration( 1293bdd1243dSDimitry Andric F->getParent(), Intrinsic::ptr_annotation, 1294bdd1243dSDimitry Andric {F->arg_begin()->getType(), F->getArg(1)->getType()}); 1295d409305fSDimitry Andric return true; 12968bcb0991SDimitry Andric } 12978bcb0991SDimitry Andric break; 12988bcb0991SDimitry Andric 12995f757f3fSDimitry Andric case 'r': { 13005f757f3fSDimitry Andric if (Name.consume_front("riscv.")) { 13015f757f3fSDimitry Andric Intrinsic::ID ID; 13025f757f3fSDimitry Andric ID = StringSwitch<Intrinsic::ID>(Name) 13035f757f3fSDimitry Andric .Case("aes32dsi", Intrinsic::riscv_aes32dsi) 13045f757f3fSDimitry Andric .Case("aes32dsmi", Intrinsic::riscv_aes32dsmi) 13055f757f3fSDimitry Andric .Case("aes32esi", Intrinsic::riscv_aes32esi) 13065f757f3fSDimitry Andric .Case("aes32esmi", Intrinsic::riscv_aes32esmi) 13075f757f3fSDimitry Andric .Default(Intrinsic::not_intrinsic); 13085f757f3fSDimitry Andric if (ID != Intrinsic::not_intrinsic) { 13095f757f3fSDimitry Andric if (!F->getFunctionType()->getParamType(2)->isIntegerTy(32)) { 131006c3fb27SDimitry Andric rename(F); 13115f757f3fSDimitry Andric NewFn = Intrinsic::getDeclaration(F->getParent(), ID); 131206c3fb27SDimitry Andric return true; 131306c3fb27SDimitry Andric } 13145f757f3fSDimitry Andric break; // No other applicable upgrades. 131506c3fb27SDimitry Andric } 13165f757f3fSDimitry Andric 13175f757f3fSDimitry Andric ID = StringSwitch<Intrinsic::ID>(Name) 13185f757f3fSDimitry Andric .StartsWith("sm4ks", Intrinsic::riscv_sm4ks) 13195f757f3fSDimitry Andric .StartsWith("sm4ed", Intrinsic::riscv_sm4ed) 13205f757f3fSDimitry Andric .Default(Intrinsic::not_intrinsic); 13215f757f3fSDimitry Andric if (ID != Intrinsic::not_intrinsic) { 13225f757f3fSDimitry Andric if (!F->getFunctionType()->getParamType(2)->isIntegerTy(32) || 132306c3fb27SDimitry Andric F->getFunctionType()->getReturnType()->isIntegerTy(64)) { 132406c3fb27SDimitry Andric rename(F); 13255f757f3fSDimitry Andric NewFn = Intrinsic::getDeclaration(F->getParent(), ID); 132606c3fb27SDimitry Andric return true; 132706c3fb27SDimitry Andric } 13285f757f3fSDimitry Andric break; // No other applicable upgrades. 13295f757f3fSDimitry Andric } 13305f757f3fSDimitry Andric 13315f757f3fSDimitry Andric ID = StringSwitch<Intrinsic::ID>(Name) 13325f757f3fSDimitry Andric .StartsWith("sha256sig0", Intrinsic::riscv_sha256sig0) 13335f757f3fSDimitry Andric .StartsWith("sha256sig1", Intrinsic::riscv_sha256sig1) 13345f757f3fSDimitry Andric .StartsWith("sha256sum0", Intrinsic::riscv_sha256sum0) 13355f757f3fSDimitry Andric .StartsWith("sha256sum1", Intrinsic::riscv_sha256sum1) 13365f757f3fSDimitry Andric .StartsWith("sm3p0", Intrinsic::riscv_sm3p0) 13375f757f3fSDimitry Andric .StartsWith("sm3p1", Intrinsic::riscv_sm3p1) 13385f757f3fSDimitry Andric .Default(Intrinsic::not_intrinsic); 13395f757f3fSDimitry Andric if (ID != Intrinsic::not_intrinsic) { 13405f757f3fSDimitry Andric if (F->getFunctionType()->getReturnType()->isIntegerTy(64)) { 134106c3fb27SDimitry Andric rename(F); 13425f757f3fSDimitry Andric NewFn = Intrinsic::getDeclaration(F->getParent(), ID); 134306c3fb27SDimitry Andric return true; 134406c3fb27SDimitry Andric } 13455f757f3fSDimitry Andric break; // No other applicable upgrades. 134606c3fb27SDimitry Andric } 13475f757f3fSDimitry Andric break; // No other 'riscv.*' intrinsics 134806c3fb27SDimitry Andric } 13495f757f3fSDimitry Andric } break; 135006c3fb27SDimitry Andric 13510b57cec5SDimitry Andric case 's': 13520b57cec5SDimitry Andric if (Name == "stackprotectorcheck") { 13530b57cec5SDimitry Andric NewFn = nullptr; 13540b57cec5SDimitry Andric return true; 13550b57cec5SDimitry Andric } 13560b57cec5SDimitry Andric break; 13570b57cec5SDimitry Andric 1358d409305fSDimitry Andric case 'v': { 1359d409305fSDimitry Andric if (Name == "var.annotation" && F->arg_size() == 4) { 1360d409305fSDimitry Andric rename(F); 1361bdd1243dSDimitry Andric NewFn = Intrinsic::getDeclaration( 1362bdd1243dSDimitry Andric F->getParent(), Intrinsic::var_annotation, 1363bdd1243dSDimitry Andric {{F->arg_begin()->getType(), F->getArg(1)->getType()}}); 1364d409305fSDimitry Andric return true; 1365d409305fSDimitry Andric } 1366d409305fSDimitry Andric break; 1367d409305fSDimitry Andric } 1368d409305fSDimitry Andric 13691ac55f4cSDimitry Andric case 'w': 13705f757f3fSDimitry Andric if (Name.consume_front("wasm.")) { 13715f757f3fSDimitry Andric Intrinsic::ID ID = 13725f757f3fSDimitry Andric StringSwitch<Intrinsic::ID>(Name) 13735f757f3fSDimitry Andric .StartsWith("fma.", Intrinsic::wasm_relaxed_madd) 13745f757f3fSDimitry Andric .StartsWith("fms.", Intrinsic::wasm_relaxed_nmadd) 13755f757f3fSDimitry Andric .StartsWith("laneselect.", Intrinsic::wasm_relaxed_laneselect) 13765f757f3fSDimitry Andric .Default(Intrinsic::not_intrinsic); 13775f757f3fSDimitry Andric if (ID != Intrinsic::not_intrinsic) { 13781ac55f4cSDimitry Andric rename(F); 13795f757f3fSDimitry Andric NewFn = 13805f757f3fSDimitry Andric Intrinsic::getDeclaration(F->getParent(), ID, F->getReturnType()); 13811ac55f4cSDimitry Andric return true; 13821ac55f4cSDimitry Andric } 13835f757f3fSDimitry Andric 13845f757f3fSDimitry Andric if (Name.consume_front("dot.i8x16.i7x16.")) { 13855f757f3fSDimitry Andric ID = StringSwitch<Intrinsic::ID>(Name) 13865f757f3fSDimitry Andric .Case("signed", Intrinsic::wasm_relaxed_dot_i8x16_i7x16_signed) 13875f757f3fSDimitry Andric .Case("add.signed", 13885f757f3fSDimitry Andric Intrinsic::wasm_relaxed_dot_i8x16_i7x16_add_signed) 13895f757f3fSDimitry Andric .Default(Intrinsic::not_intrinsic); 13905f757f3fSDimitry Andric if (ID != Intrinsic::not_intrinsic) { 13911ac55f4cSDimitry Andric rename(F); 13925f757f3fSDimitry Andric NewFn = Intrinsic::getDeclaration(F->getParent(), ID); 13931ac55f4cSDimitry Andric return true; 13941ac55f4cSDimitry Andric } 13955f757f3fSDimitry Andric break; // No other 'wasm.dot.i8x16.i7x16.*'. 13961ac55f4cSDimitry Andric } 13975f757f3fSDimitry Andric break; // No other 'wasm.*'. 13981ac55f4cSDimitry Andric } 13991ac55f4cSDimitry Andric break; 14001ac55f4cSDimitry Andric 14010b57cec5SDimitry Andric case 'x': 14027a6dacacSDimitry Andric if (upgradeX86IntrinsicFunction(F, Name, NewFn)) 14030b57cec5SDimitry Andric return true; 14040b57cec5SDimitry Andric } 140581ad6265SDimitry Andric 140681ad6265SDimitry Andric auto *ST = dyn_cast<StructType>(F->getReturnType()); 14075f757f3fSDimitry Andric if (ST && (!ST->isLiteral() || ST->isPacked()) && 14085f757f3fSDimitry Andric F->getIntrinsicID() != Intrinsic::not_intrinsic) { 140981ad6265SDimitry Andric // Replace return type with literal non-packed struct. Only do this for 141081ad6265SDimitry Andric // intrinsics declared to return a struct, not for intrinsics with 141181ad6265SDimitry Andric // overloaded return type, in which case the exact struct type will be 141281ad6265SDimitry Andric // mangled into the name. 141381ad6265SDimitry Andric SmallVector<Intrinsic::IITDescriptor> Desc; 141481ad6265SDimitry Andric Intrinsic::getIntrinsicInfoTableEntries(F->getIntrinsicID(), Desc); 141581ad6265SDimitry Andric if (Desc.front().Kind == Intrinsic::IITDescriptor::Struct) { 141681ad6265SDimitry Andric auto *FT = F->getFunctionType(); 141781ad6265SDimitry Andric auto *NewST = StructType::get(ST->getContext(), ST->elements()); 141881ad6265SDimitry Andric auto *NewFT = FunctionType::get(NewST, FT->params(), FT->isVarArg()); 141981ad6265SDimitry Andric std::string Name = F->getName().str(); 142081ad6265SDimitry Andric rename(F); 142181ad6265SDimitry Andric NewFn = Function::Create(NewFT, F->getLinkage(), F->getAddressSpace(), 142281ad6265SDimitry Andric Name, F->getParent()); 142381ad6265SDimitry Andric 142481ad6265SDimitry Andric // The new function may also need remangling. 1425f3fd488fSDimitry Andric if (auto Result = llvm::Intrinsic::remangleIntrinsicFunction(NewFn)) 142681ad6265SDimitry Andric NewFn = *Result; 142781ad6265SDimitry Andric return true; 142881ad6265SDimitry Andric } 142981ad6265SDimitry Andric } 143081ad6265SDimitry Andric 14310b57cec5SDimitry Andric // Remangle our intrinsic since we upgrade the mangling 14320b57cec5SDimitry Andric auto Result = llvm::Intrinsic::remangleIntrinsicFunction(F); 1433bdd1243dSDimitry Andric if (Result != std::nullopt) { 143481ad6265SDimitry Andric NewFn = *Result; 14350b57cec5SDimitry Andric return true; 14360b57cec5SDimitry Andric } 14370b57cec5SDimitry Andric 14380b57cec5SDimitry Andric // This may not belong here. This function is effectively being overloaded 14390b57cec5SDimitry Andric // to both detect an intrinsic which needs upgrading, and to provide the 14400b57cec5SDimitry Andric // upgraded form of the intrinsic. We should perhaps have two separate 14410b57cec5SDimitry Andric // functions for this. 14420b57cec5SDimitry Andric return false; 14430b57cec5SDimitry Andric } 14440b57cec5SDimitry Andric 1445*0fca6ea1SDimitry Andric bool llvm::UpgradeIntrinsicFunction(Function *F, Function *&NewFn, 1446*0fca6ea1SDimitry Andric bool CanUpgradeDebugIntrinsicsToRecords) { 14470b57cec5SDimitry Andric NewFn = nullptr; 1448*0fca6ea1SDimitry Andric bool Upgraded = 1449*0fca6ea1SDimitry Andric upgradeIntrinsicFunction1(F, NewFn, CanUpgradeDebugIntrinsicsToRecords); 14500b57cec5SDimitry Andric assert(F != NewFn && "Intrinsic function upgraded to the same function"); 14510b57cec5SDimitry Andric 14520b57cec5SDimitry Andric // Upgrade intrinsic attributes. This does not change the function. 14530b57cec5SDimitry Andric if (NewFn) 14540b57cec5SDimitry Andric F = NewFn; 14550b57cec5SDimitry Andric if (Intrinsic::ID id = F->getIntrinsicID()) 14560b57cec5SDimitry Andric F->setAttributes(Intrinsic::getAttributes(F->getContext(), id)); 14570b57cec5SDimitry Andric return Upgraded; 14580b57cec5SDimitry Andric } 14590b57cec5SDimitry Andric 14600b57cec5SDimitry Andric GlobalVariable *llvm::UpgradeGlobalVariable(GlobalVariable *GV) { 14610b57cec5SDimitry Andric if (!(GV->hasName() && (GV->getName() == "llvm.global_ctors" || 14620b57cec5SDimitry Andric GV->getName() == "llvm.global_dtors")) || 14630b57cec5SDimitry Andric !GV->hasInitializer()) 14640b57cec5SDimitry Andric return nullptr; 14650b57cec5SDimitry Andric ArrayType *ATy = dyn_cast<ArrayType>(GV->getValueType()); 14660b57cec5SDimitry Andric if (!ATy) 14670b57cec5SDimitry Andric return nullptr; 14680b57cec5SDimitry Andric StructType *STy = dyn_cast<StructType>(ATy->getElementType()); 14690b57cec5SDimitry Andric if (!STy || STy->getNumElements() != 2) 14700b57cec5SDimitry Andric return nullptr; 14710b57cec5SDimitry Andric 14720b57cec5SDimitry Andric LLVMContext &C = GV->getContext(); 14730b57cec5SDimitry Andric IRBuilder<> IRB(C); 14740b57cec5SDimitry Andric auto EltTy = StructType::get(STy->getElementType(0), STy->getElementType(1), 14755f757f3fSDimitry Andric IRB.getPtrTy()); 14760b57cec5SDimitry Andric Constant *Init = GV->getInitializer(); 14770b57cec5SDimitry Andric unsigned N = Init->getNumOperands(); 14780b57cec5SDimitry Andric std::vector<Constant *> NewCtors(N); 14790b57cec5SDimitry Andric for (unsigned i = 0; i != N; ++i) { 14800b57cec5SDimitry Andric auto Ctor = cast<Constant>(Init->getOperand(i)); 14815f757f3fSDimitry Andric NewCtors[i] = ConstantStruct::get(EltTy, Ctor->getAggregateElement(0u), 14825f757f3fSDimitry Andric Ctor->getAggregateElement(1), 14835f757f3fSDimitry Andric Constant::getNullValue(IRB.getPtrTy())); 14840b57cec5SDimitry Andric } 14850b57cec5SDimitry Andric Constant *NewInit = ConstantArray::get(ArrayType::get(EltTy, N), NewCtors); 14860b57cec5SDimitry Andric 14870b57cec5SDimitry Andric return new GlobalVariable(NewInit->getType(), false, GV->getLinkage(), 14880b57cec5SDimitry Andric NewInit, GV->getName()); 14890b57cec5SDimitry Andric } 14900b57cec5SDimitry Andric 14910b57cec5SDimitry Andric // Handles upgrading SSE2/AVX2/AVX512BW PSLLDQ intrinsics by converting them 14920b57cec5SDimitry Andric // to byte shuffles. 14937a6dacacSDimitry Andric static Value *upgradeX86PSLLDQIntrinsics(IRBuilder<> &Builder, Value *Op, 14947a6dacacSDimitry Andric unsigned Shift) { 1495e8d8bef9SDimitry Andric auto *ResultTy = cast<FixedVectorType>(Op->getType()); 14965ffd83dbSDimitry Andric unsigned NumElts = ResultTy->getNumElements() * 8; 14970b57cec5SDimitry Andric 14980b57cec5SDimitry Andric // Bitcast from a 64-bit element type to a byte element type. 14995ffd83dbSDimitry Andric Type *VecTy = FixedVectorType::get(Builder.getInt8Ty(), NumElts); 15000b57cec5SDimitry Andric Op = Builder.CreateBitCast(Op, VecTy, "cast"); 15010b57cec5SDimitry Andric 15020b57cec5SDimitry Andric // We'll be shuffling in zeroes. 15030b57cec5SDimitry Andric Value *Res = Constant::getNullValue(VecTy); 15040b57cec5SDimitry Andric 15050b57cec5SDimitry Andric // If shift is less than 16, emit a shuffle to move the bytes. Otherwise, 15060b57cec5SDimitry Andric // we'll just return the zero vector. 15070b57cec5SDimitry Andric if (Shift < 16) { 15085ffd83dbSDimitry Andric int Idxs[64]; 15090b57cec5SDimitry Andric // 256/512-bit version is split into 2/4 16-byte lanes. 15100b57cec5SDimitry Andric for (unsigned l = 0; l != NumElts; l += 16) 15110b57cec5SDimitry Andric for (unsigned i = 0; i != 16; ++i) { 15120b57cec5SDimitry Andric unsigned Idx = NumElts + i - Shift; 15130b57cec5SDimitry Andric if (Idx < NumElts) 15140b57cec5SDimitry Andric Idx -= NumElts - 16; // end of lane, switch operand. 15150b57cec5SDimitry Andric Idxs[l + i] = Idx + l; 15160b57cec5SDimitry Andric } 15170b57cec5SDimitry Andric 1518bdd1243dSDimitry Andric Res = Builder.CreateShuffleVector(Res, Op, ArrayRef(Idxs, NumElts)); 15190b57cec5SDimitry Andric } 15200b57cec5SDimitry Andric 15210b57cec5SDimitry Andric // Bitcast back to a 64-bit element type. 15220b57cec5SDimitry Andric return Builder.CreateBitCast(Res, ResultTy, "cast"); 15230b57cec5SDimitry Andric } 15240b57cec5SDimitry Andric 15250b57cec5SDimitry Andric // Handles upgrading SSE2/AVX2/AVX512BW PSRLDQ intrinsics by converting them 15260b57cec5SDimitry Andric // to byte shuffles. 15277a6dacacSDimitry Andric static Value *upgradeX86PSRLDQIntrinsics(IRBuilder<> &Builder, Value *Op, 15280b57cec5SDimitry Andric unsigned Shift) { 1529e8d8bef9SDimitry Andric auto *ResultTy = cast<FixedVectorType>(Op->getType()); 15305ffd83dbSDimitry Andric unsigned NumElts = ResultTy->getNumElements() * 8; 15310b57cec5SDimitry Andric 15320b57cec5SDimitry Andric // Bitcast from a 64-bit element type to a byte element type. 15335ffd83dbSDimitry Andric Type *VecTy = FixedVectorType::get(Builder.getInt8Ty(), NumElts); 15340b57cec5SDimitry Andric Op = Builder.CreateBitCast(Op, VecTy, "cast"); 15350b57cec5SDimitry Andric 15360b57cec5SDimitry Andric // We'll be shuffling in zeroes. 15370b57cec5SDimitry Andric Value *Res = Constant::getNullValue(VecTy); 15380b57cec5SDimitry Andric 15390b57cec5SDimitry Andric // If shift is less than 16, emit a shuffle to move the bytes. Otherwise, 15400b57cec5SDimitry Andric // we'll just return the zero vector. 15410b57cec5SDimitry Andric if (Shift < 16) { 15425ffd83dbSDimitry Andric int Idxs[64]; 15430b57cec5SDimitry Andric // 256/512-bit version is split into 2/4 16-byte lanes. 15440b57cec5SDimitry Andric for (unsigned l = 0; l != NumElts; l += 16) 15450b57cec5SDimitry Andric for (unsigned i = 0; i != 16; ++i) { 15460b57cec5SDimitry Andric unsigned Idx = i + Shift; 15470b57cec5SDimitry Andric if (Idx >= 16) 15480b57cec5SDimitry Andric Idx += NumElts - 16; // end of lane, switch operand. 15490b57cec5SDimitry Andric Idxs[l + i] = Idx + l; 15500b57cec5SDimitry Andric } 15510b57cec5SDimitry Andric 1552bdd1243dSDimitry Andric Res = Builder.CreateShuffleVector(Op, Res, ArrayRef(Idxs, NumElts)); 15530b57cec5SDimitry Andric } 15540b57cec5SDimitry Andric 15550b57cec5SDimitry Andric // Bitcast back to a 64-bit element type. 15560b57cec5SDimitry Andric return Builder.CreateBitCast(Res, ResultTy, "cast"); 15570b57cec5SDimitry Andric } 15580b57cec5SDimitry Andric 15590b57cec5SDimitry Andric static Value *getX86MaskVec(IRBuilder<> &Builder, Value *Mask, 15600b57cec5SDimitry Andric unsigned NumElts) { 1561e8d8bef9SDimitry Andric assert(isPowerOf2_32(NumElts) && "Expected power-of-2 mask elements"); 15625ffd83dbSDimitry Andric llvm::VectorType *MaskTy = FixedVectorType::get( 15635ffd83dbSDimitry Andric Builder.getInt1Ty(), cast<IntegerType>(Mask->getType())->getBitWidth()); 15640b57cec5SDimitry Andric Mask = Builder.CreateBitCast(Mask, MaskTy); 15650b57cec5SDimitry Andric 1566e8d8bef9SDimitry Andric // If we have less than 8 elements (1, 2 or 4), then the starting mask was an 1567e8d8bef9SDimitry Andric // i8 and we need to extract down to the right number of elements. 1568e8d8bef9SDimitry Andric if (NumElts <= 4) { 15695ffd83dbSDimitry Andric int Indices[4]; 15700b57cec5SDimitry Andric for (unsigned i = 0; i != NumElts; ++i) 15710b57cec5SDimitry Andric Indices[i] = i; 1572bdd1243dSDimitry Andric Mask = Builder.CreateShuffleVector(Mask, Mask, ArrayRef(Indices, NumElts), 1573bdd1243dSDimitry Andric "extract"); 15740b57cec5SDimitry Andric } 15750b57cec5SDimitry Andric 15760b57cec5SDimitry Andric return Mask; 15770b57cec5SDimitry Andric } 15780b57cec5SDimitry Andric 15797a6dacacSDimitry Andric static Value *emitX86Select(IRBuilder<> &Builder, Value *Mask, Value *Op0, 15807a6dacacSDimitry Andric Value *Op1) { 15810b57cec5SDimitry Andric // If the mask is all ones just emit the first operation. 15820b57cec5SDimitry Andric if (const auto *C = dyn_cast<Constant>(Mask)) 15830b57cec5SDimitry Andric if (C->isAllOnesValue()) 15840b57cec5SDimitry Andric return Op0; 15850b57cec5SDimitry Andric 15865ffd83dbSDimitry Andric Mask = getX86MaskVec(Builder, Mask, 1587e8d8bef9SDimitry Andric cast<FixedVectorType>(Op0->getType())->getNumElements()); 15880b57cec5SDimitry Andric return Builder.CreateSelect(Mask, Op0, Op1); 15890b57cec5SDimitry Andric } 15900b57cec5SDimitry Andric 15917a6dacacSDimitry Andric static Value *emitX86ScalarSelect(IRBuilder<> &Builder, Value *Mask, Value *Op0, 15927a6dacacSDimitry Andric Value *Op1) { 15930b57cec5SDimitry Andric // If the mask is all ones just emit the first operation. 15940b57cec5SDimitry Andric if (const auto *C = dyn_cast<Constant>(Mask)) 15950b57cec5SDimitry Andric if (C->isAllOnesValue()) 15960b57cec5SDimitry Andric return Op0; 15970b57cec5SDimitry Andric 15985ffd83dbSDimitry Andric auto *MaskTy = FixedVectorType::get(Builder.getInt1Ty(), 15990b57cec5SDimitry Andric Mask->getType()->getIntegerBitWidth()); 16000b57cec5SDimitry Andric Mask = Builder.CreateBitCast(Mask, MaskTy); 16010b57cec5SDimitry Andric Mask = Builder.CreateExtractElement(Mask, (uint64_t)0); 16020b57cec5SDimitry Andric return Builder.CreateSelect(Mask, Op0, Op1); 16030b57cec5SDimitry Andric } 16040b57cec5SDimitry Andric 16050b57cec5SDimitry Andric // Handle autoupgrade for masked PALIGNR and VALIGND/Q intrinsics. 16060b57cec5SDimitry Andric // PALIGNR handles large immediates by shifting while VALIGN masks the immediate 16070b57cec5SDimitry Andric // so we need to handle both cases. VALIGN also doesn't have 128-bit lanes. 16087a6dacacSDimitry Andric static Value *upgradeX86ALIGNIntrinsics(IRBuilder<> &Builder, Value *Op0, 16090b57cec5SDimitry Andric Value *Op1, Value *Shift, 16100b57cec5SDimitry Andric Value *Passthru, Value *Mask, 16110b57cec5SDimitry Andric bool IsVALIGN) { 16120b57cec5SDimitry Andric unsigned ShiftVal = cast<llvm::ConstantInt>(Shift)->getZExtValue(); 16130b57cec5SDimitry Andric 1614e8d8bef9SDimitry Andric unsigned NumElts = cast<FixedVectorType>(Op0->getType())->getNumElements(); 16150b57cec5SDimitry Andric assert((IsVALIGN || NumElts % 16 == 0) && "Illegal NumElts for PALIGNR!"); 16160b57cec5SDimitry Andric assert((!IsVALIGN || NumElts <= 16) && "NumElts too large for VALIGN!"); 16170b57cec5SDimitry Andric assert(isPowerOf2_32(NumElts) && "NumElts not a power of 2!"); 16180b57cec5SDimitry Andric 16190b57cec5SDimitry Andric // Mask the immediate for VALIGN. 16200b57cec5SDimitry Andric if (IsVALIGN) 16210b57cec5SDimitry Andric ShiftVal &= (NumElts - 1); 16220b57cec5SDimitry Andric 16230b57cec5SDimitry Andric // If palignr is shifting the pair of vectors more than the size of two 16240b57cec5SDimitry Andric // lanes, emit zero. 16250b57cec5SDimitry Andric if (ShiftVal >= 32) 16260b57cec5SDimitry Andric return llvm::Constant::getNullValue(Op0->getType()); 16270b57cec5SDimitry Andric 16280b57cec5SDimitry Andric // If palignr is shifting the pair of input vectors more than one lane, 16290b57cec5SDimitry Andric // but less than two lanes, convert to shifting in zeroes. 16300b57cec5SDimitry Andric if (ShiftVal > 16) { 16310b57cec5SDimitry Andric ShiftVal -= 16; 16320b57cec5SDimitry Andric Op1 = Op0; 16330b57cec5SDimitry Andric Op0 = llvm::Constant::getNullValue(Op0->getType()); 16340b57cec5SDimitry Andric } 16350b57cec5SDimitry Andric 16365ffd83dbSDimitry Andric int Indices[64]; 16370b57cec5SDimitry Andric // 256-bit palignr operates on 128-bit lanes so we need to handle that 16380b57cec5SDimitry Andric for (unsigned l = 0; l < NumElts; l += 16) { 16390b57cec5SDimitry Andric for (unsigned i = 0; i != 16; ++i) { 16400b57cec5SDimitry Andric unsigned Idx = ShiftVal + i; 16410b57cec5SDimitry Andric if (!IsVALIGN && Idx >= 16) // Disable wrap for VALIGN. 16420b57cec5SDimitry Andric Idx += NumElts - 16; // End of lane, switch operand. 16430b57cec5SDimitry Andric Indices[l + i] = Idx + l; 16440b57cec5SDimitry Andric } 16450b57cec5SDimitry Andric } 16460b57cec5SDimitry Andric 1647bdd1243dSDimitry Andric Value *Align = Builder.CreateShuffleVector( 1648bdd1243dSDimitry Andric Op1, Op0, ArrayRef(Indices, NumElts), "palignr"); 16490b57cec5SDimitry Andric 16507a6dacacSDimitry Andric return emitX86Select(Builder, Mask, Align, Passthru); 16510b57cec5SDimitry Andric } 16520b57cec5SDimitry Andric 16537a6dacacSDimitry Andric static Value *upgradeX86VPERMT2Intrinsics(IRBuilder<> &Builder, CallBase &CI, 16540b57cec5SDimitry Andric bool ZeroMask, bool IndexForm) { 16550b57cec5SDimitry Andric Type *Ty = CI.getType(); 16560b57cec5SDimitry Andric unsigned VecWidth = Ty->getPrimitiveSizeInBits(); 16570b57cec5SDimitry Andric unsigned EltWidth = Ty->getScalarSizeInBits(); 16580b57cec5SDimitry Andric bool IsFloat = Ty->isFPOrFPVectorTy(); 16590b57cec5SDimitry Andric Intrinsic::ID IID; 16600b57cec5SDimitry Andric if (VecWidth == 128 && EltWidth == 32 && IsFloat) 16610b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_vpermi2var_ps_128; 16620b57cec5SDimitry Andric else if (VecWidth == 128 && EltWidth == 32 && !IsFloat) 16630b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_vpermi2var_d_128; 16640b57cec5SDimitry Andric else if (VecWidth == 128 && EltWidth == 64 && IsFloat) 16650b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_vpermi2var_pd_128; 16660b57cec5SDimitry Andric else if (VecWidth == 128 && EltWidth == 64 && !IsFloat) 16670b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_vpermi2var_q_128; 16680b57cec5SDimitry Andric else if (VecWidth == 256 && EltWidth == 32 && IsFloat) 16690b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_vpermi2var_ps_256; 16700b57cec5SDimitry Andric else if (VecWidth == 256 && EltWidth == 32 && !IsFloat) 16710b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_vpermi2var_d_256; 16720b57cec5SDimitry Andric else if (VecWidth == 256 && EltWidth == 64 && IsFloat) 16730b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_vpermi2var_pd_256; 16740b57cec5SDimitry Andric else if (VecWidth == 256 && EltWidth == 64 && !IsFloat) 16750b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_vpermi2var_q_256; 16760b57cec5SDimitry Andric else if (VecWidth == 512 && EltWidth == 32 && IsFloat) 16770b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_vpermi2var_ps_512; 16780b57cec5SDimitry Andric else if (VecWidth == 512 && EltWidth == 32 && !IsFloat) 16790b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_vpermi2var_d_512; 16800b57cec5SDimitry Andric else if (VecWidth == 512 && EltWidth == 64 && IsFloat) 16810b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_vpermi2var_pd_512; 16820b57cec5SDimitry Andric else if (VecWidth == 512 && EltWidth == 64 && !IsFloat) 16830b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_vpermi2var_q_512; 16840b57cec5SDimitry Andric else if (VecWidth == 128 && EltWidth == 16) 16850b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_vpermi2var_hi_128; 16860b57cec5SDimitry Andric else if (VecWidth == 256 && EltWidth == 16) 16870b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_vpermi2var_hi_256; 16880b57cec5SDimitry Andric else if (VecWidth == 512 && EltWidth == 16) 16890b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_vpermi2var_hi_512; 16900b57cec5SDimitry Andric else if (VecWidth == 128 && EltWidth == 8) 16910b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_vpermi2var_qi_128; 16920b57cec5SDimitry Andric else if (VecWidth == 256 && EltWidth == 8) 16930b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_vpermi2var_qi_256; 16940b57cec5SDimitry Andric else if (VecWidth == 512 && EltWidth == 8) 16950b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_vpermi2var_qi_512; 16960b57cec5SDimitry Andric else 16970b57cec5SDimitry Andric llvm_unreachable("Unexpected intrinsic"); 16980b57cec5SDimitry Andric 16990b57cec5SDimitry Andric Value *Args[] = { CI.getArgOperand(0) , CI.getArgOperand(1), 17000b57cec5SDimitry Andric CI.getArgOperand(2) }; 17010b57cec5SDimitry Andric 17020b57cec5SDimitry Andric // If this isn't index form we need to swap operand 0 and 1. 17030b57cec5SDimitry Andric if (!IndexForm) 17040b57cec5SDimitry Andric std::swap(Args[0], Args[1]); 17050b57cec5SDimitry Andric 17060b57cec5SDimitry Andric Value *V = Builder.CreateCall(Intrinsic::getDeclaration(CI.getModule(), IID), 17070b57cec5SDimitry Andric Args); 17080b57cec5SDimitry Andric Value *PassThru = ZeroMask ? ConstantAggregateZero::get(Ty) 17090b57cec5SDimitry Andric : Builder.CreateBitCast(CI.getArgOperand(1), 17100b57cec5SDimitry Andric Ty); 17117a6dacacSDimitry Andric return emitX86Select(Builder, CI.getArgOperand(3), V, PassThru); 17120b57cec5SDimitry Andric } 17130b57cec5SDimitry Andric 17147a6dacacSDimitry Andric static Value *upgradeX86BinaryIntrinsics(IRBuilder<> &Builder, CallBase &CI, 1715e8d8bef9SDimitry Andric Intrinsic::ID IID) { 17160b57cec5SDimitry Andric Type *Ty = CI.getType(); 17170b57cec5SDimitry Andric Value *Op0 = CI.getOperand(0); 17180b57cec5SDimitry Andric Value *Op1 = CI.getOperand(1); 17190b57cec5SDimitry Andric Function *Intrin = Intrinsic::getDeclaration(CI.getModule(), IID, Ty); 17200b57cec5SDimitry Andric Value *Res = Builder.CreateCall(Intrin, {Op0, Op1}); 17210b57cec5SDimitry Andric 1722349cc55cSDimitry Andric if (CI.arg_size() == 4) { // For masked intrinsics. 17230b57cec5SDimitry Andric Value *VecSrc = CI.getOperand(2); 17240b57cec5SDimitry Andric Value *Mask = CI.getOperand(3); 17257a6dacacSDimitry Andric Res = emitX86Select(Builder, Mask, Res, VecSrc); 17260b57cec5SDimitry Andric } 17270b57cec5SDimitry Andric return Res; 17280b57cec5SDimitry Andric } 17290b57cec5SDimitry Andric 173081ad6265SDimitry Andric static Value *upgradeX86Rotate(IRBuilder<> &Builder, CallBase &CI, 17310b57cec5SDimitry Andric bool IsRotateRight) { 17320b57cec5SDimitry Andric Type *Ty = CI.getType(); 17330b57cec5SDimitry Andric Value *Src = CI.getArgOperand(0); 17340b57cec5SDimitry Andric Value *Amt = CI.getArgOperand(1); 17350b57cec5SDimitry Andric 17360b57cec5SDimitry Andric // Amount may be scalar immediate, in which case create a splat vector. 17370b57cec5SDimitry Andric // Funnel shifts amounts are treated as modulo and types are all power-of-2 so 17380b57cec5SDimitry Andric // we only care about the lowest log2 bits anyway. 17390b57cec5SDimitry Andric if (Amt->getType() != Ty) { 1740e8d8bef9SDimitry Andric unsigned NumElts = cast<FixedVectorType>(Ty)->getNumElements(); 17410b57cec5SDimitry Andric Amt = Builder.CreateIntCast(Amt, Ty->getScalarType(), false); 17420b57cec5SDimitry Andric Amt = Builder.CreateVectorSplat(NumElts, Amt); 17430b57cec5SDimitry Andric } 17440b57cec5SDimitry Andric 17450b57cec5SDimitry Andric Intrinsic::ID IID = IsRotateRight ? Intrinsic::fshr : Intrinsic::fshl; 17460b57cec5SDimitry Andric Function *Intrin = Intrinsic::getDeclaration(CI.getModule(), IID, Ty); 17470b57cec5SDimitry Andric Value *Res = Builder.CreateCall(Intrin, {Src, Src, Amt}); 17480b57cec5SDimitry Andric 1749349cc55cSDimitry Andric if (CI.arg_size() == 4) { // For masked intrinsics. 17500b57cec5SDimitry Andric Value *VecSrc = CI.getOperand(2); 17510b57cec5SDimitry Andric Value *Mask = CI.getOperand(3); 17527a6dacacSDimitry Andric Res = emitX86Select(Builder, Mask, Res, VecSrc); 17530b57cec5SDimitry Andric } 17540b57cec5SDimitry Andric return Res; 17550b57cec5SDimitry Andric } 17560b57cec5SDimitry Andric 175781ad6265SDimitry Andric static Value *upgradeX86vpcom(IRBuilder<> &Builder, CallBase &CI, unsigned Imm, 17580b57cec5SDimitry Andric bool IsSigned) { 17590b57cec5SDimitry Andric Type *Ty = CI.getType(); 17600b57cec5SDimitry Andric Value *LHS = CI.getArgOperand(0); 17610b57cec5SDimitry Andric Value *RHS = CI.getArgOperand(1); 17620b57cec5SDimitry Andric 17630b57cec5SDimitry Andric CmpInst::Predicate Pred; 17640b57cec5SDimitry Andric switch (Imm) { 17650b57cec5SDimitry Andric case 0x0: 17660b57cec5SDimitry Andric Pred = IsSigned ? ICmpInst::ICMP_SLT : ICmpInst::ICMP_ULT; 17670b57cec5SDimitry Andric break; 17680b57cec5SDimitry Andric case 0x1: 17690b57cec5SDimitry Andric Pred = IsSigned ? ICmpInst::ICMP_SLE : ICmpInst::ICMP_ULE; 17700b57cec5SDimitry Andric break; 17710b57cec5SDimitry Andric case 0x2: 17720b57cec5SDimitry Andric Pred = IsSigned ? ICmpInst::ICMP_SGT : ICmpInst::ICMP_UGT; 17730b57cec5SDimitry Andric break; 17740b57cec5SDimitry Andric case 0x3: 17750b57cec5SDimitry Andric Pred = IsSigned ? ICmpInst::ICMP_SGE : ICmpInst::ICMP_UGE; 17760b57cec5SDimitry Andric break; 17770b57cec5SDimitry Andric case 0x4: 17780b57cec5SDimitry Andric Pred = ICmpInst::ICMP_EQ; 17790b57cec5SDimitry Andric break; 17800b57cec5SDimitry Andric case 0x5: 17810b57cec5SDimitry Andric Pred = ICmpInst::ICMP_NE; 17820b57cec5SDimitry Andric break; 17830b57cec5SDimitry Andric case 0x6: 17840b57cec5SDimitry Andric return Constant::getNullValue(Ty); // FALSE 17850b57cec5SDimitry Andric case 0x7: 17860b57cec5SDimitry Andric return Constant::getAllOnesValue(Ty); // TRUE 17870b57cec5SDimitry Andric default: 17880b57cec5SDimitry Andric llvm_unreachable("Unknown XOP vpcom/vpcomu predicate"); 17890b57cec5SDimitry Andric } 17900b57cec5SDimitry Andric 17910b57cec5SDimitry Andric Value *Cmp = Builder.CreateICmp(Pred, LHS, RHS); 17920b57cec5SDimitry Andric Value *Ext = Builder.CreateSExt(Cmp, Ty); 17930b57cec5SDimitry Andric return Ext; 17940b57cec5SDimitry Andric } 17950b57cec5SDimitry Andric 179681ad6265SDimitry Andric static Value *upgradeX86ConcatShift(IRBuilder<> &Builder, CallBase &CI, 17970b57cec5SDimitry Andric bool IsShiftRight, bool ZeroMask) { 17980b57cec5SDimitry Andric Type *Ty = CI.getType(); 17990b57cec5SDimitry Andric Value *Op0 = CI.getArgOperand(0); 18000b57cec5SDimitry Andric Value *Op1 = CI.getArgOperand(1); 18010b57cec5SDimitry Andric Value *Amt = CI.getArgOperand(2); 18020b57cec5SDimitry Andric 18030b57cec5SDimitry Andric if (IsShiftRight) 18040b57cec5SDimitry Andric std::swap(Op0, Op1); 18050b57cec5SDimitry Andric 18060b57cec5SDimitry Andric // Amount may be scalar immediate, in which case create a splat vector. 18070b57cec5SDimitry Andric // Funnel shifts amounts are treated as modulo and types are all power-of-2 so 18080b57cec5SDimitry Andric // we only care about the lowest log2 bits anyway. 18090b57cec5SDimitry Andric if (Amt->getType() != Ty) { 1810e8d8bef9SDimitry Andric unsigned NumElts = cast<FixedVectorType>(Ty)->getNumElements(); 18110b57cec5SDimitry Andric Amt = Builder.CreateIntCast(Amt, Ty->getScalarType(), false); 18120b57cec5SDimitry Andric Amt = Builder.CreateVectorSplat(NumElts, Amt); 18130b57cec5SDimitry Andric } 18140b57cec5SDimitry Andric 18150b57cec5SDimitry Andric Intrinsic::ID IID = IsShiftRight ? Intrinsic::fshr : Intrinsic::fshl; 18160b57cec5SDimitry Andric Function *Intrin = Intrinsic::getDeclaration(CI.getModule(), IID, Ty); 18170b57cec5SDimitry Andric Value *Res = Builder.CreateCall(Intrin, {Op0, Op1, Amt}); 18180b57cec5SDimitry Andric 1819349cc55cSDimitry Andric unsigned NumArgs = CI.arg_size(); 18200b57cec5SDimitry Andric if (NumArgs >= 4) { // For masked intrinsics. 18210b57cec5SDimitry Andric Value *VecSrc = NumArgs == 5 ? CI.getArgOperand(3) : 18220b57cec5SDimitry Andric ZeroMask ? ConstantAggregateZero::get(CI.getType()) : 18230b57cec5SDimitry Andric CI.getArgOperand(0); 18240b57cec5SDimitry Andric Value *Mask = CI.getOperand(NumArgs - 1); 18257a6dacacSDimitry Andric Res = emitX86Select(Builder, Mask, Res, VecSrc); 18260b57cec5SDimitry Andric } 18270b57cec5SDimitry Andric return Res; 18280b57cec5SDimitry Andric } 18290b57cec5SDimitry Andric 18307a6dacacSDimitry Andric static Value *upgradeMaskedStore(IRBuilder<> &Builder, Value *Ptr, Value *Data, 18317a6dacacSDimitry Andric Value *Mask, bool Aligned) { 18320b57cec5SDimitry Andric // Cast the pointer to the right type. 18330b57cec5SDimitry Andric Ptr = Builder.CreateBitCast(Ptr, 18340b57cec5SDimitry Andric llvm::PointerType::getUnqual(Data->getType())); 18355ffd83dbSDimitry Andric const Align Alignment = 18365ffd83dbSDimitry Andric Aligned 1837bdd1243dSDimitry Andric ? Align(Data->getType()->getPrimitiveSizeInBits().getFixedValue() / 8) 18385ffd83dbSDimitry Andric : Align(1); 18390b57cec5SDimitry Andric 18400b57cec5SDimitry Andric // If the mask is all ones just emit a regular store. 18410b57cec5SDimitry Andric if (const auto *C = dyn_cast<Constant>(Mask)) 18420b57cec5SDimitry Andric if (C->isAllOnesValue()) 18435ffd83dbSDimitry Andric return Builder.CreateAlignedStore(Data, Ptr, Alignment); 18440b57cec5SDimitry Andric 18450b57cec5SDimitry Andric // Convert the mask from an integer type to a vector of i1. 1846e8d8bef9SDimitry Andric unsigned NumElts = cast<FixedVectorType>(Data->getType())->getNumElements(); 18470b57cec5SDimitry Andric Mask = getX86MaskVec(Builder, Mask, NumElts); 18485ffd83dbSDimitry Andric return Builder.CreateMaskedStore(Data, Ptr, Alignment, Mask); 18490b57cec5SDimitry Andric } 18500b57cec5SDimitry Andric 18517a6dacacSDimitry Andric static Value *upgradeMaskedLoad(IRBuilder<> &Builder, Value *Ptr, 18527a6dacacSDimitry Andric Value *Passthru, Value *Mask, bool Aligned) { 18530b57cec5SDimitry Andric Type *ValTy = Passthru->getType(); 18540b57cec5SDimitry Andric // Cast the pointer to the right type. 18550b57cec5SDimitry Andric Ptr = Builder.CreateBitCast(Ptr, llvm::PointerType::getUnqual(ValTy)); 18565ffd83dbSDimitry Andric const Align Alignment = 18575ffd83dbSDimitry Andric Aligned 1858bdd1243dSDimitry Andric ? Align( 1859bdd1243dSDimitry Andric Passthru->getType()->getPrimitiveSizeInBits().getFixedValue() / 18605ffd83dbSDimitry Andric 8) 18615ffd83dbSDimitry Andric : Align(1); 18620b57cec5SDimitry Andric 18630b57cec5SDimitry Andric // If the mask is all ones just emit a regular store. 18640b57cec5SDimitry Andric if (const auto *C = dyn_cast<Constant>(Mask)) 18650b57cec5SDimitry Andric if (C->isAllOnesValue()) 18665ffd83dbSDimitry Andric return Builder.CreateAlignedLoad(ValTy, Ptr, Alignment); 18670b57cec5SDimitry Andric 18680b57cec5SDimitry Andric // Convert the mask from an integer type to a vector of i1. 1869fe6060f1SDimitry Andric unsigned NumElts = cast<FixedVectorType>(ValTy)->getNumElements(); 18700b57cec5SDimitry Andric Mask = getX86MaskVec(Builder, Mask, NumElts); 1871fe6060f1SDimitry Andric return Builder.CreateMaskedLoad(ValTy, Ptr, Alignment, Mask, Passthru); 18720b57cec5SDimitry Andric } 18730b57cec5SDimitry Andric 187481ad6265SDimitry Andric static Value *upgradeAbs(IRBuilder<> &Builder, CallBase &CI) { 1875e8d8bef9SDimitry Andric Type *Ty = CI.getType(); 18760b57cec5SDimitry Andric Value *Op0 = CI.getArgOperand(0); 1877e8d8bef9SDimitry Andric Function *F = Intrinsic::getDeclaration(CI.getModule(), Intrinsic::abs, Ty); 1878e8d8bef9SDimitry Andric Value *Res = Builder.CreateCall(F, {Op0, Builder.getInt1(false)}); 1879349cc55cSDimitry Andric if (CI.arg_size() == 3) 18807a6dacacSDimitry Andric Res = emitX86Select(Builder, CI.getArgOperand(2), Res, CI.getArgOperand(1)); 18810b57cec5SDimitry Andric return Res; 18820b57cec5SDimitry Andric } 18830b57cec5SDimitry Andric 188481ad6265SDimitry Andric static Value *upgradePMULDQ(IRBuilder<> &Builder, CallBase &CI, bool IsSigned) { 18850b57cec5SDimitry Andric Type *Ty = CI.getType(); 18860b57cec5SDimitry Andric 18870b57cec5SDimitry Andric // Arguments have a vXi32 type so cast to vXi64. 18880b57cec5SDimitry Andric Value *LHS = Builder.CreateBitCast(CI.getArgOperand(0), Ty); 18890b57cec5SDimitry Andric Value *RHS = Builder.CreateBitCast(CI.getArgOperand(1), Ty); 18900b57cec5SDimitry Andric 18910b57cec5SDimitry Andric if (IsSigned) { 18920b57cec5SDimitry Andric // Shift left then arithmetic shift right. 18930b57cec5SDimitry Andric Constant *ShiftAmt = ConstantInt::get(Ty, 32); 18940b57cec5SDimitry Andric LHS = Builder.CreateShl(LHS, ShiftAmt); 18950b57cec5SDimitry Andric LHS = Builder.CreateAShr(LHS, ShiftAmt); 18960b57cec5SDimitry Andric RHS = Builder.CreateShl(RHS, ShiftAmt); 18970b57cec5SDimitry Andric RHS = Builder.CreateAShr(RHS, ShiftAmt); 18980b57cec5SDimitry Andric } else { 18990b57cec5SDimitry Andric // Clear the upper bits. 19000b57cec5SDimitry Andric Constant *Mask = ConstantInt::get(Ty, 0xffffffff); 19010b57cec5SDimitry Andric LHS = Builder.CreateAnd(LHS, Mask); 19020b57cec5SDimitry Andric RHS = Builder.CreateAnd(RHS, Mask); 19030b57cec5SDimitry Andric } 19040b57cec5SDimitry Andric 19050b57cec5SDimitry Andric Value *Res = Builder.CreateMul(LHS, RHS); 19060b57cec5SDimitry Andric 1907349cc55cSDimitry Andric if (CI.arg_size() == 4) 19087a6dacacSDimitry Andric Res = emitX86Select(Builder, CI.getArgOperand(3), Res, CI.getArgOperand(2)); 19090b57cec5SDimitry Andric 19100b57cec5SDimitry Andric return Res; 19110b57cec5SDimitry Andric } 19120b57cec5SDimitry Andric 19130b57cec5SDimitry Andric // Applying mask on vector of i1's and make sure result is at least 8 bits wide. 19147a6dacacSDimitry Andric static Value *applyX86MaskOn1BitsVec(IRBuilder<> &Builder, Value *Vec, 19150b57cec5SDimitry Andric Value *Mask) { 1916e8d8bef9SDimitry Andric unsigned NumElts = cast<FixedVectorType>(Vec->getType())->getNumElements(); 19170b57cec5SDimitry Andric if (Mask) { 19180b57cec5SDimitry Andric const auto *C = dyn_cast<Constant>(Mask); 19190b57cec5SDimitry Andric if (!C || !C->isAllOnesValue()) 19200b57cec5SDimitry Andric Vec = Builder.CreateAnd(Vec, getX86MaskVec(Builder, Mask, NumElts)); 19210b57cec5SDimitry Andric } 19220b57cec5SDimitry Andric 19230b57cec5SDimitry Andric if (NumElts < 8) { 19245ffd83dbSDimitry Andric int Indices[8]; 19250b57cec5SDimitry Andric for (unsigned i = 0; i != NumElts; ++i) 19260b57cec5SDimitry Andric Indices[i] = i; 19270b57cec5SDimitry Andric for (unsigned i = NumElts; i != 8; ++i) 19280b57cec5SDimitry Andric Indices[i] = NumElts + i % NumElts; 19290b57cec5SDimitry Andric Vec = Builder.CreateShuffleVector(Vec, 19300b57cec5SDimitry Andric Constant::getNullValue(Vec->getType()), 19310b57cec5SDimitry Andric Indices); 19320b57cec5SDimitry Andric } 19330b57cec5SDimitry Andric return Builder.CreateBitCast(Vec, Builder.getIntNTy(std::max(NumElts, 8U))); 19340b57cec5SDimitry Andric } 19350b57cec5SDimitry Andric 193681ad6265SDimitry Andric static Value *upgradeMaskedCompare(IRBuilder<> &Builder, CallBase &CI, 19370b57cec5SDimitry Andric unsigned CC, bool Signed) { 19380b57cec5SDimitry Andric Value *Op0 = CI.getArgOperand(0); 1939e8d8bef9SDimitry Andric unsigned NumElts = cast<FixedVectorType>(Op0->getType())->getNumElements(); 19400b57cec5SDimitry Andric 19410b57cec5SDimitry Andric Value *Cmp; 19420b57cec5SDimitry Andric if (CC == 3) { 19435ffd83dbSDimitry Andric Cmp = Constant::getNullValue( 19445ffd83dbSDimitry Andric FixedVectorType::get(Builder.getInt1Ty(), NumElts)); 19450b57cec5SDimitry Andric } else if (CC == 7) { 19465ffd83dbSDimitry Andric Cmp = Constant::getAllOnesValue( 19475ffd83dbSDimitry Andric FixedVectorType::get(Builder.getInt1Ty(), NumElts)); 19480b57cec5SDimitry Andric } else { 19490b57cec5SDimitry Andric ICmpInst::Predicate Pred; 19500b57cec5SDimitry Andric switch (CC) { 19510b57cec5SDimitry Andric default: llvm_unreachable("Unknown condition code"); 19520b57cec5SDimitry Andric case 0: Pred = ICmpInst::ICMP_EQ; break; 19530b57cec5SDimitry Andric case 1: Pred = Signed ? ICmpInst::ICMP_SLT : ICmpInst::ICMP_ULT; break; 19540b57cec5SDimitry Andric case 2: Pred = Signed ? ICmpInst::ICMP_SLE : ICmpInst::ICMP_ULE; break; 19550b57cec5SDimitry Andric case 4: Pred = ICmpInst::ICMP_NE; break; 19560b57cec5SDimitry Andric case 5: Pred = Signed ? ICmpInst::ICMP_SGE : ICmpInst::ICMP_UGE; break; 19570b57cec5SDimitry Andric case 6: Pred = Signed ? ICmpInst::ICMP_SGT : ICmpInst::ICMP_UGT; break; 19580b57cec5SDimitry Andric } 19590b57cec5SDimitry Andric Cmp = Builder.CreateICmp(Pred, Op0, CI.getArgOperand(1)); 19600b57cec5SDimitry Andric } 19610b57cec5SDimitry Andric 1962349cc55cSDimitry Andric Value *Mask = CI.getArgOperand(CI.arg_size() - 1); 19630b57cec5SDimitry Andric 19647a6dacacSDimitry Andric return applyX86MaskOn1BitsVec(Builder, Cmp, Mask); 19650b57cec5SDimitry Andric } 19660b57cec5SDimitry Andric 19670b57cec5SDimitry Andric // Replace a masked intrinsic with an older unmasked intrinsic. 19687a6dacacSDimitry Andric static Value *upgradeX86MaskedShift(IRBuilder<> &Builder, CallBase &CI, 19690b57cec5SDimitry Andric Intrinsic::ID IID) { 19700b57cec5SDimitry Andric Function *Intrin = Intrinsic::getDeclaration(CI.getModule(), IID); 19710b57cec5SDimitry Andric Value *Rep = Builder.CreateCall(Intrin, 19720b57cec5SDimitry Andric { CI.getArgOperand(0), CI.getArgOperand(1) }); 19737a6dacacSDimitry Andric return emitX86Select(Builder, CI.getArgOperand(3), Rep, CI.getArgOperand(2)); 19740b57cec5SDimitry Andric } 19750b57cec5SDimitry Andric 197681ad6265SDimitry Andric static Value *upgradeMaskedMove(IRBuilder<> &Builder, CallBase &CI) { 19770b57cec5SDimitry Andric Value* A = CI.getArgOperand(0); 19780b57cec5SDimitry Andric Value* B = CI.getArgOperand(1); 19790b57cec5SDimitry Andric Value* Src = CI.getArgOperand(2); 19800b57cec5SDimitry Andric Value* Mask = CI.getArgOperand(3); 19810b57cec5SDimitry Andric 19820b57cec5SDimitry Andric Value* AndNode = Builder.CreateAnd(Mask, APInt(8, 1)); 19830b57cec5SDimitry Andric Value* Cmp = Builder.CreateIsNotNull(AndNode); 19840b57cec5SDimitry Andric Value* Extract1 = Builder.CreateExtractElement(B, (uint64_t)0); 19850b57cec5SDimitry Andric Value* Extract2 = Builder.CreateExtractElement(Src, (uint64_t)0); 19860b57cec5SDimitry Andric Value* Select = Builder.CreateSelect(Cmp, Extract1, Extract2); 19870b57cec5SDimitry Andric return Builder.CreateInsertElement(A, Select, (uint64_t)0); 19880b57cec5SDimitry Andric } 19890b57cec5SDimitry Andric 19907a6dacacSDimitry Andric static Value *upgradeMaskToInt(IRBuilder<> &Builder, CallBase &CI) { 19910b57cec5SDimitry Andric Value* Op = CI.getArgOperand(0); 19920b57cec5SDimitry Andric Type* ReturnOp = CI.getType(); 1993e8d8bef9SDimitry Andric unsigned NumElts = cast<FixedVectorType>(CI.getType())->getNumElements(); 19940b57cec5SDimitry Andric Value *Mask = getX86MaskVec(Builder, Op, NumElts); 19950b57cec5SDimitry Andric return Builder.CreateSExt(Mask, ReturnOp, "vpmovm2"); 19960b57cec5SDimitry Andric } 19970b57cec5SDimitry Andric 19980b57cec5SDimitry Andric // Replace intrinsic with unmasked version and a select. 19990b57cec5SDimitry Andric static bool upgradeAVX512MaskToSelect(StringRef Name, IRBuilder<> &Builder, 200081ad6265SDimitry Andric CallBase &CI, Value *&Rep) { 20010b57cec5SDimitry Andric Name = Name.substr(12); // Remove avx512.mask. 20020b57cec5SDimitry Andric 20030b57cec5SDimitry Andric unsigned VecWidth = CI.getType()->getPrimitiveSizeInBits(); 20040b57cec5SDimitry Andric unsigned EltWidth = CI.getType()->getScalarSizeInBits(); 20050b57cec5SDimitry Andric Intrinsic::ID IID; 20065f757f3fSDimitry Andric if (Name.starts_with("max.p")) { 20070b57cec5SDimitry Andric if (VecWidth == 128 && EltWidth == 32) 20080b57cec5SDimitry Andric IID = Intrinsic::x86_sse_max_ps; 20090b57cec5SDimitry Andric else if (VecWidth == 128 && EltWidth == 64) 20100b57cec5SDimitry Andric IID = Intrinsic::x86_sse2_max_pd; 20110b57cec5SDimitry Andric else if (VecWidth == 256 && EltWidth == 32) 20120b57cec5SDimitry Andric IID = Intrinsic::x86_avx_max_ps_256; 20130b57cec5SDimitry Andric else if (VecWidth == 256 && EltWidth == 64) 20140b57cec5SDimitry Andric IID = Intrinsic::x86_avx_max_pd_256; 20150b57cec5SDimitry Andric else 20160b57cec5SDimitry Andric llvm_unreachable("Unexpected intrinsic"); 20175f757f3fSDimitry Andric } else if (Name.starts_with("min.p")) { 20180b57cec5SDimitry Andric if (VecWidth == 128 && EltWidth == 32) 20190b57cec5SDimitry Andric IID = Intrinsic::x86_sse_min_ps; 20200b57cec5SDimitry Andric else if (VecWidth == 128 && EltWidth == 64) 20210b57cec5SDimitry Andric IID = Intrinsic::x86_sse2_min_pd; 20220b57cec5SDimitry Andric else if (VecWidth == 256 && EltWidth == 32) 20230b57cec5SDimitry Andric IID = Intrinsic::x86_avx_min_ps_256; 20240b57cec5SDimitry Andric else if (VecWidth == 256 && EltWidth == 64) 20250b57cec5SDimitry Andric IID = Intrinsic::x86_avx_min_pd_256; 20260b57cec5SDimitry Andric else 20270b57cec5SDimitry Andric llvm_unreachable("Unexpected intrinsic"); 20285f757f3fSDimitry Andric } else if (Name.starts_with("pshuf.b.")) { 20290b57cec5SDimitry Andric if (VecWidth == 128) 20300b57cec5SDimitry Andric IID = Intrinsic::x86_ssse3_pshuf_b_128; 20310b57cec5SDimitry Andric else if (VecWidth == 256) 20320b57cec5SDimitry Andric IID = Intrinsic::x86_avx2_pshuf_b; 20330b57cec5SDimitry Andric else if (VecWidth == 512) 20340b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_pshuf_b_512; 20350b57cec5SDimitry Andric else 20360b57cec5SDimitry Andric llvm_unreachable("Unexpected intrinsic"); 20375f757f3fSDimitry Andric } else if (Name.starts_with("pmul.hr.sw.")) { 20380b57cec5SDimitry Andric if (VecWidth == 128) 20390b57cec5SDimitry Andric IID = Intrinsic::x86_ssse3_pmul_hr_sw_128; 20400b57cec5SDimitry Andric else if (VecWidth == 256) 20410b57cec5SDimitry Andric IID = Intrinsic::x86_avx2_pmul_hr_sw; 20420b57cec5SDimitry Andric else if (VecWidth == 512) 20430b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_pmul_hr_sw_512; 20440b57cec5SDimitry Andric else 20450b57cec5SDimitry Andric llvm_unreachable("Unexpected intrinsic"); 20465f757f3fSDimitry Andric } else if (Name.starts_with("pmulh.w.")) { 20470b57cec5SDimitry Andric if (VecWidth == 128) 20480b57cec5SDimitry Andric IID = Intrinsic::x86_sse2_pmulh_w; 20490b57cec5SDimitry Andric else if (VecWidth == 256) 20500b57cec5SDimitry Andric IID = Intrinsic::x86_avx2_pmulh_w; 20510b57cec5SDimitry Andric else if (VecWidth == 512) 20520b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_pmulh_w_512; 20530b57cec5SDimitry Andric else 20540b57cec5SDimitry Andric llvm_unreachable("Unexpected intrinsic"); 20555f757f3fSDimitry Andric } else if (Name.starts_with("pmulhu.w.")) { 20560b57cec5SDimitry Andric if (VecWidth == 128) 20570b57cec5SDimitry Andric IID = Intrinsic::x86_sse2_pmulhu_w; 20580b57cec5SDimitry Andric else if (VecWidth == 256) 20590b57cec5SDimitry Andric IID = Intrinsic::x86_avx2_pmulhu_w; 20600b57cec5SDimitry Andric else if (VecWidth == 512) 20610b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_pmulhu_w_512; 20620b57cec5SDimitry Andric else 20630b57cec5SDimitry Andric llvm_unreachable("Unexpected intrinsic"); 20645f757f3fSDimitry Andric } else if (Name.starts_with("pmaddw.d.")) { 20650b57cec5SDimitry Andric if (VecWidth == 128) 20660b57cec5SDimitry Andric IID = Intrinsic::x86_sse2_pmadd_wd; 20670b57cec5SDimitry Andric else if (VecWidth == 256) 20680b57cec5SDimitry Andric IID = Intrinsic::x86_avx2_pmadd_wd; 20690b57cec5SDimitry Andric else if (VecWidth == 512) 20700b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_pmaddw_d_512; 20710b57cec5SDimitry Andric else 20720b57cec5SDimitry Andric llvm_unreachable("Unexpected intrinsic"); 20735f757f3fSDimitry Andric } else if (Name.starts_with("pmaddubs.w.")) { 20740b57cec5SDimitry Andric if (VecWidth == 128) 20750b57cec5SDimitry Andric IID = Intrinsic::x86_ssse3_pmadd_ub_sw_128; 20760b57cec5SDimitry Andric else if (VecWidth == 256) 20770b57cec5SDimitry Andric IID = Intrinsic::x86_avx2_pmadd_ub_sw; 20780b57cec5SDimitry Andric else if (VecWidth == 512) 20790b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_pmaddubs_w_512; 20800b57cec5SDimitry Andric else 20810b57cec5SDimitry Andric llvm_unreachable("Unexpected intrinsic"); 20825f757f3fSDimitry Andric } else if (Name.starts_with("packsswb.")) { 20830b57cec5SDimitry Andric if (VecWidth == 128) 20840b57cec5SDimitry Andric IID = Intrinsic::x86_sse2_packsswb_128; 20850b57cec5SDimitry Andric else if (VecWidth == 256) 20860b57cec5SDimitry Andric IID = Intrinsic::x86_avx2_packsswb; 20870b57cec5SDimitry Andric else if (VecWidth == 512) 20880b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_packsswb_512; 20890b57cec5SDimitry Andric else 20900b57cec5SDimitry Andric llvm_unreachable("Unexpected intrinsic"); 20915f757f3fSDimitry Andric } else if (Name.starts_with("packssdw.")) { 20920b57cec5SDimitry Andric if (VecWidth == 128) 20930b57cec5SDimitry Andric IID = Intrinsic::x86_sse2_packssdw_128; 20940b57cec5SDimitry Andric else if (VecWidth == 256) 20950b57cec5SDimitry Andric IID = Intrinsic::x86_avx2_packssdw; 20960b57cec5SDimitry Andric else if (VecWidth == 512) 20970b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_packssdw_512; 20980b57cec5SDimitry Andric else 20990b57cec5SDimitry Andric llvm_unreachable("Unexpected intrinsic"); 21005f757f3fSDimitry Andric } else if (Name.starts_with("packuswb.")) { 21010b57cec5SDimitry Andric if (VecWidth == 128) 21020b57cec5SDimitry Andric IID = Intrinsic::x86_sse2_packuswb_128; 21030b57cec5SDimitry Andric else if (VecWidth == 256) 21040b57cec5SDimitry Andric IID = Intrinsic::x86_avx2_packuswb; 21050b57cec5SDimitry Andric else if (VecWidth == 512) 21060b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_packuswb_512; 21070b57cec5SDimitry Andric else 21080b57cec5SDimitry Andric llvm_unreachable("Unexpected intrinsic"); 21095f757f3fSDimitry Andric } else if (Name.starts_with("packusdw.")) { 21100b57cec5SDimitry Andric if (VecWidth == 128) 21110b57cec5SDimitry Andric IID = Intrinsic::x86_sse41_packusdw; 21120b57cec5SDimitry Andric else if (VecWidth == 256) 21130b57cec5SDimitry Andric IID = Intrinsic::x86_avx2_packusdw; 21140b57cec5SDimitry Andric else if (VecWidth == 512) 21150b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_packusdw_512; 21160b57cec5SDimitry Andric else 21170b57cec5SDimitry Andric llvm_unreachable("Unexpected intrinsic"); 21185f757f3fSDimitry Andric } else if (Name.starts_with("vpermilvar.")) { 21190b57cec5SDimitry Andric if (VecWidth == 128 && EltWidth == 32) 21200b57cec5SDimitry Andric IID = Intrinsic::x86_avx_vpermilvar_ps; 21210b57cec5SDimitry Andric else if (VecWidth == 128 && EltWidth == 64) 21220b57cec5SDimitry Andric IID = Intrinsic::x86_avx_vpermilvar_pd; 21230b57cec5SDimitry Andric else if (VecWidth == 256 && EltWidth == 32) 21240b57cec5SDimitry Andric IID = Intrinsic::x86_avx_vpermilvar_ps_256; 21250b57cec5SDimitry Andric else if (VecWidth == 256 && EltWidth == 64) 21260b57cec5SDimitry Andric IID = Intrinsic::x86_avx_vpermilvar_pd_256; 21270b57cec5SDimitry Andric else if (VecWidth == 512 && EltWidth == 32) 21280b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_vpermilvar_ps_512; 21290b57cec5SDimitry Andric else if (VecWidth == 512 && EltWidth == 64) 21300b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_vpermilvar_pd_512; 21310b57cec5SDimitry Andric else 21320b57cec5SDimitry Andric llvm_unreachable("Unexpected intrinsic"); 21330b57cec5SDimitry Andric } else if (Name == "cvtpd2dq.256") { 21340b57cec5SDimitry Andric IID = Intrinsic::x86_avx_cvt_pd2dq_256; 21350b57cec5SDimitry Andric } else if (Name == "cvtpd2ps.256") { 21360b57cec5SDimitry Andric IID = Intrinsic::x86_avx_cvt_pd2_ps_256; 21370b57cec5SDimitry Andric } else if (Name == "cvttpd2dq.256") { 21380b57cec5SDimitry Andric IID = Intrinsic::x86_avx_cvtt_pd2dq_256; 21390b57cec5SDimitry Andric } else if (Name == "cvttps2dq.128") { 21400b57cec5SDimitry Andric IID = Intrinsic::x86_sse2_cvttps2dq; 21410b57cec5SDimitry Andric } else if (Name == "cvttps2dq.256") { 21420b57cec5SDimitry Andric IID = Intrinsic::x86_avx_cvtt_ps2dq_256; 21435f757f3fSDimitry Andric } else if (Name.starts_with("permvar.")) { 21440b57cec5SDimitry Andric bool IsFloat = CI.getType()->isFPOrFPVectorTy(); 21450b57cec5SDimitry Andric if (VecWidth == 256 && EltWidth == 32 && IsFloat) 21460b57cec5SDimitry Andric IID = Intrinsic::x86_avx2_permps; 21470b57cec5SDimitry Andric else if (VecWidth == 256 && EltWidth == 32 && !IsFloat) 21480b57cec5SDimitry Andric IID = Intrinsic::x86_avx2_permd; 21490b57cec5SDimitry Andric else if (VecWidth == 256 && EltWidth == 64 && IsFloat) 21500b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_permvar_df_256; 21510b57cec5SDimitry Andric else if (VecWidth == 256 && EltWidth == 64 && !IsFloat) 21520b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_permvar_di_256; 21530b57cec5SDimitry Andric else if (VecWidth == 512 && EltWidth == 32 && IsFloat) 21540b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_permvar_sf_512; 21550b57cec5SDimitry Andric else if (VecWidth == 512 && EltWidth == 32 && !IsFloat) 21560b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_permvar_si_512; 21570b57cec5SDimitry Andric else if (VecWidth == 512 && EltWidth == 64 && IsFloat) 21580b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_permvar_df_512; 21590b57cec5SDimitry Andric else if (VecWidth == 512 && EltWidth == 64 && !IsFloat) 21600b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_permvar_di_512; 21610b57cec5SDimitry Andric else if (VecWidth == 128 && EltWidth == 16) 21620b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_permvar_hi_128; 21630b57cec5SDimitry Andric else if (VecWidth == 256 && EltWidth == 16) 21640b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_permvar_hi_256; 21650b57cec5SDimitry Andric else if (VecWidth == 512 && EltWidth == 16) 21660b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_permvar_hi_512; 21670b57cec5SDimitry Andric else if (VecWidth == 128 && EltWidth == 8) 21680b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_permvar_qi_128; 21690b57cec5SDimitry Andric else if (VecWidth == 256 && EltWidth == 8) 21700b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_permvar_qi_256; 21710b57cec5SDimitry Andric else if (VecWidth == 512 && EltWidth == 8) 21720b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_permvar_qi_512; 21730b57cec5SDimitry Andric else 21740b57cec5SDimitry Andric llvm_unreachable("Unexpected intrinsic"); 21755f757f3fSDimitry Andric } else if (Name.starts_with("dbpsadbw.")) { 21760b57cec5SDimitry Andric if (VecWidth == 128) 21770b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_dbpsadbw_128; 21780b57cec5SDimitry Andric else if (VecWidth == 256) 21790b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_dbpsadbw_256; 21800b57cec5SDimitry Andric else if (VecWidth == 512) 21810b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_dbpsadbw_512; 21820b57cec5SDimitry Andric else 21830b57cec5SDimitry Andric llvm_unreachable("Unexpected intrinsic"); 21845f757f3fSDimitry Andric } else if (Name.starts_with("pmultishift.qb.")) { 21850b57cec5SDimitry Andric if (VecWidth == 128) 21860b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_pmultishift_qb_128; 21870b57cec5SDimitry Andric else if (VecWidth == 256) 21880b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_pmultishift_qb_256; 21890b57cec5SDimitry Andric else if (VecWidth == 512) 21900b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_pmultishift_qb_512; 21910b57cec5SDimitry Andric else 21920b57cec5SDimitry Andric llvm_unreachable("Unexpected intrinsic"); 21935f757f3fSDimitry Andric } else if (Name.starts_with("conflict.")) { 21940b57cec5SDimitry Andric if (Name[9] == 'd' && VecWidth == 128) 21950b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_conflict_d_128; 21960b57cec5SDimitry Andric else if (Name[9] == 'd' && VecWidth == 256) 21970b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_conflict_d_256; 21980b57cec5SDimitry Andric else if (Name[9] == 'd' && VecWidth == 512) 21990b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_conflict_d_512; 22000b57cec5SDimitry Andric else if (Name[9] == 'q' && VecWidth == 128) 22010b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_conflict_q_128; 22020b57cec5SDimitry Andric else if (Name[9] == 'q' && VecWidth == 256) 22030b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_conflict_q_256; 22040b57cec5SDimitry Andric else if (Name[9] == 'q' && VecWidth == 512) 22050b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_conflict_q_512; 22060b57cec5SDimitry Andric else 22070b57cec5SDimitry Andric llvm_unreachable("Unexpected intrinsic"); 22085f757f3fSDimitry Andric } else if (Name.starts_with("pavg.")) { 22090b57cec5SDimitry Andric if (Name[5] == 'b' && VecWidth == 128) 22100b57cec5SDimitry Andric IID = Intrinsic::x86_sse2_pavg_b; 22110b57cec5SDimitry Andric else if (Name[5] == 'b' && VecWidth == 256) 22120b57cec5SDimitry Andric IID = Intrinsic::x86_avx2_pavg_b; 22130b57cec5SDimitry Andric else if (Name[5] == 'b' && VecWidth == 512) 22140b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_pavg_b_512; 22150b57cec5SDimitry Andric else if (Name[5] == 'w' && VecWidth == 128) 22160b57cec5SDimitry Andric IID = Intrinsic::x86_sse2_pavg_w; 22170b57cec5SDimitry Andric else if (Name[5] == 'w' && VecWidth == 256) 22180b57cec5SDimitry Andric IID = Intrinsic::x86_avx2_pavg_w; 22190b57cec5SDimitry Andric else if (Name[5] == 'w' && VecWidth == 512) 22200b57cec5SDimitry Andric IID = Intrinsic::x86_avx512_pavg_w_512; 22210b57cec5SDimitry Andric else 22220b57cec5SDimitry Andric llvm_unreachable("Unexpected intrinsic"); 22230b57cec5SDimitry Andric } else 22240b57cec5SDimitry Andric return false; 22250b57cec5SDimitry Andric 2226349cc55cSDimitry Andric SmallVector<Value *, 4> Args(CI.args()); 22270b57cec5SDimitry Andric Args.pop_back(); 22280b57cec5SDimitry Andric Args.pop_back(); 22290b57cec5SDimitry Andric Rep = Builder.CreateCall(Intrinsic::getDeclaration(CI.getModule(), IID), 22300b57cec5SDimitry Andric Args); 2231349cc55cSDimitry Andric unsigned NumArgs = CI.arg_size(); 22327a6dacacSDimitry Andric Rep = emitX86Select(Builder, CI.getArgOperand(NumArgs - 1), Rep, 22330b57cec5SDimitry Andric CI.getArgOperand(NumArgs - 2)); 22340b57cec5SDimitry Andric return true; 22350b57cec5SDimitry Andric } 22360b57cec5SDimitry Andric 22370b57cec5SDimitry Andric /// Upgrade comment in call to inline asm that represents an objc retain release 22380b57cec5SDimitry Andric /// marker. 22390b57cec5SDimitry Andric void llvm::UpgradeInlineAsmString(std::string *AsmStr) { 22400b57cec5SDimitry Andric size_t Pos; 22410b57cec5SDimitry Andric if (AsmStr->find("mov\tfp") == 0 && 22420b57cec5SDimitry Andric AsmStr->find("objc_retainAutoreleaseReturnValue") != std::string::npos && 22430b57cec5SDimitry Andric (Pos = AsmStr->find("# marker")) != std::string::npos) { 22440b57cec5SDimitry Andric AsmStr->replace(Pos, 1, ";"); 22450b57cec5SDimitry Andric } 22460b57cec5SDimitry Andric } 22470b57cec5SDimitry Andric 2248*0fca6ea1SDimitry Andric static Value *upgradeX86IntrinsicCall(StringRef Name, CallBase *CI, Function *F, 2249*0fca6ea1SDimitry Andric IRBuilder<> &Builder) { 2250*0fca6ea1SDimitry Andric LLVMContext &C = F->getContext(); 2251*0fca6ea1SDimitry Andric Value *Rep = nullptr; 2252*0fca6ea1SDimitry Andric 2253*0fca6ea1SDimitry Andric if (Name.starts_with("sse4a.movnt.")) { 2254*0fca6ea1SDimitry Andric SmallVector<Metadata *, 1> Elts; 2255*0fca6ea1SDimitry Andric Elts.push_back( 2256*0fca6ea1SDimitry Andric ConstantAsMetadata::get(ConstantInt::get(Type::getInt32Ty(C), 1))); 2257*0fca6ea1SDimitry Andric MDNode *Node = MDNode::get(C, Elts); 2258*0fca6ea1SDimitry Andric 2259*0fca6ea1SDimitry Andric Value *Arg0 = CI->getArgOperand(0); 2260*0fca6ea1SDimitry Andric Value *Arg1 = CI->getArgOperand(1); 2261*0fca6ea1SDimitry Andric 2262*0fca6ea1SDimitry Andric // Nontemporal (unaligned) store of the 0'th element of the float/double 2263*0fca6ea1SDimitry Andric // vector. 2264*0fca6ea1SDimitry Andric Type *SrcEltTy = cast<VectorType>(Arg1->getType())->getElementType(); 2265*0fca6ea1SDimitry Andric PointerType *EltPtrTy = PointerType::getUnqual(SrcEltTy); 2266*0fca6ea1SDimitry Andric Value *Addr = Builder.CreateBitCast(Arg0, EltPtrTy, "cast"); 2267*0fca6ea1SDimitry Andric Value *Extract = 2268*0fca6ea1SDimitry Andric Builder.CreateExtractElement(Arg1, (uint64_t)0, "extractelement"); 2269*0fca6ea1SDimitry Andric 2270*0fca6ea1SDimitry Andric StoreInst *SI = Builder.CreateAlignedStore(Extract, Addr, Align(1)); 2271*0fca6ea1SDimitry Andric SI->setMetadata(LLVMContext::MD_nontemporal, Node); 2272*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx.movnt.") || 2273*0fca6ea1SDimitry Andric Name.starts_with("avx512.storent.")) { 2274*0fca6ea1SDimitry Andric SmallVector<Metadata *, 1> Elts; 2275*0fca6ea1SDimitry Andric Elts.push_back( 2276*0fca6ea1SDimitry Andric ConstantAsMetadata::get(ConstantInt::get(Type::getInt32Ty(C), 1))); 2277*0fca6ea1SDimitry Andric MDNode *Node = MDNode::get(C, Elts); 2278*0fca6ea1SDimitry Andric 2279*0fca6ea1SDimitry Andric Value *Arg0 = CI->getArgOperand(0); 2280*0fca6ea1SDimitry Andric Value *Arg1 = CI->getArgOperand(1); 2281*0fca6ea1SDimitry Andric 2282*0fca6ea1SDimitry Andric // Convert the type of the pointer to a pointer to the stored type. 2283*0fca6ea1SDimitry Andric Value *BC = Builder.CreateBitCast( 2284*0fca6ea1SDimitry Andric Arg0, PointerType::getUnqual(Arg1->getType()), "cast"); 2285*0fca6ea1SDimitry Andric StoreInst *SI = Builder.CreateAlignedStore( 2286*0fca6ea1SDimitry Andric Arg1, BC, 2287*0fca6ea1SDimitry Andric Align(Arg1->getType()->getPrimitiveSizeInBits().getFixedValue() / 8)); 2288*0fca6ea1SDimitry Andric SI->setMetadata(LLVMContext::MD_nontemporal, Node); 2289*0fca6ea1SDimitry Andric } else if (Name == "sse2.storel.dq") { 2290*0fca6ea1SDimitry Andric Value *Arg0 = CI->getArgOperand(0); 2291*0fca6ea1SDimitry Andric Value *Arg1 = CI->getArgOperand(1); 2292*0fca6ea1SDimitry Andric 2293*0fca6ea1SDimitry Andric auto *NewVecTy = FixedVectorType::get(Type::getInt64Ty(C), 2); 2294*0fca6ea1SDimitry Andric Value *BC0 = Builder.CreateBitCast(Arg1, NewVecTy, "cast"); 2295*0fca6ea1SDimitry Andric Value *Elt = Builder.CreateExtractElement(BC0, (uint64_t)0); 2296*0fca6ea1SDimitry Andric Value *BC = Builder.CreateBitCast( 2297*0fca6ea1SDimitry Andric Arg0, PointerType::getUnqual(Elt->getType()), "cast"); 2298*0fca6ea1SDimitry Andric Builder.CreateAlignedStore(Elt, BC, Align(1)); 2299*0fca6ea1SDimitry Andric } else if (Name.starts_with("sse.storeu.") || 2300*0fca6ea1SDimitry Andric Name.starts_with("sse2.storeu.") || 2301*0fca6ea1SDimitry Andric Name.starts_with("avx.storeu.")) { 2302*0fca6ea1SDimitry Andric Value *Arg0 = CI->getArgOperand(0); 2303*0fca6ea1SDimitry Andric Value *Arg1 = CI->getArgOperand(1); 2304*0fca6ea1SDimitry Andric 2305*0fca6ea1SDimitry Andric Arg0 = Builder.CreateBitCast(Arg0, PointerType::getUnqual(Arg1->getType()), 2306*0fca6ea1SDimitry Andric "cast"); 2307*0fca6ea1SDimitry Andric Builder.CreateAlignedStore(Arg1, Arg0, Align(1)); 2308*0fca6ea1SDimitry Andric } else if (Name == "avx512.mask.store.ss") { 2309*0fca6ea1SDimitry Andric Value *Mask = Builder.CreateAnd(CI->getArgOperand(2), Builder.getInt8(1)); 2310*0fca6ea1SDimitry Andric upgradeMaskedStore(Builder, CI->getArgOperand(0), CI->getArgOperand(1), 2311*0fca6ea1SDimitry Andric Mask, false); 2312*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.store")) { 2313*0fca6ea1SDimitry Andric // "avx512.mask.storeu." or "avx512.mask.store." 2314*0fca6ea1SDimitry Andric bool Aligned = Name[17] != 'u'; // "avx512.mask.storeu". 2315*0fca6ea1SDimitry Andric upgradeMaskedStore(Builder, CI->getArgOperand(0), CI->getArgOperand(1), 2316*0fca6ea1SDimitry Andric CI->getArgOperand(2), Aligned); 2317*0fca6ea1SDimitry Andric } else if (Name.starts_with("sse2.pcmp") || Name.starts_with("avx2.pcmp")) { 2318*0fca6ea1SDimitry Andric // Upgrade packed integer vector compare intrinsics to compare instructions. 2319*0fca6ea1SDimitry Andric // "sse2.pcpmpeq." "sse2.pcmpgt." "avx2.pcmpeq." or "avx2.pcmpgt." 2320*0fca6ea1SDimitry Andric bool CmpEq = Name[9] == 'e'; 2321*0fca6ea1SDimitry Andric Rep = Builder.CreateICmp(CmpEq ? ICmpInst::ICMP_EQ : ICmpInst::ICMP_SGT, 2322*0fca6ea1SDimitry Andric CI->getArgOperand(0), CI->getArgOperand(1)); 2323*0fca6ea1SDimitry Andric Rep = Builder.CreateSExt(Rep, CI->getType(), ""); 2324*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.broadcastm")) { 2325*0fca6ea1SDimitry Andric Type *ExtTy = Type::getInt32Ty(C); 2326*0fca6ea1SDimitry Andric if (CI->getOperand(0)->getType()->isIntegerTy(8)) 2327*0fca6ea1SDimitry Andric ExtTy = Type::getInt64Ty(C); 2328*0fca6ea1SDimitry Andric unsigned NumElts = CI->getType()->getPrimitiveSizeInBits() / 2329*0fca6ea1SDimitry Andric ExtTy->getPrimitiveSizeInBits(); 2330*0fca6ea1SDimitry Andric Rep = Builder.CreateZExt(CI->getArgOperand(0), ExtTy); 2331*0fca6ea1SDimitry Andric Rep = Builder.CreateVectorSplat(NumElts, Rep); 2332*0fca6ea1SDimitry Andric } else if (Name == "sse.sqrt.ss" || Name == "sse2.sqrt.sd") { 2333*0fca6ea1SDimitry Andric Value *Vec = CI->getArgOperand(0); 2334*0fca6ea1SDimitry Andric Value *Elt0 = Builder.CreateExtractElement(Vec, (uint64_t)0); 2335*0fca6ea1SDimitry Andric Function *Intr = Intrinsic::getDeclaration(F->getParent(), Intrinsic::sqrt, 2336*0fca6ea1SDimitry Andric Elt0->getType()); 2337*0fca6ea1SDimitry Andric Elt0 = Builder.CreateCall(Intr, Elt0); 2338*0fca6ea1SDimitry Andric Rep = Builder.CreateInsertElement(Vec, Elt0, (uint64_t)0); 2339*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx.sqrt.p") || 2340*0fca6ea1SDimitry Andric Name.starts_with("sse2.sqrt.p") || 2341*0fca6ea1SDimitry Andric Name.starts_with("sse.sqrt.p")) { 2342*0fca6ea1SDimitry Andric Rep = 2343*0fca6ea1SDimitry Andric Builder.CreateCall(Intrinsic::getDeclaration( 2344*0fca6ea1SDimitry Andric F->getParent(), Intrinsic::sqrt, CI->getType()), 2345*0fca6ea1SDimitry Andric {CI->getArgOperand(0)}); 2346*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.sqrt.p")) { 2347*0fca6ea1SDimitry Andric if (CI->arg_size() == 4 && 2348*0fca6ea1SDimitry Andric (!isa<ConstantInt>(CI->getArgOperand(3)) || 2349*0fca6ea1SDimitry Andric cast<ConstantInt>(CI->getArgOperand(3))->getZExtValue() != 4)) { 2350*0fca6ea1SDimitry Andric Intrinsic::ID IID = Name[18] == 's' ? Intrinsic::x86_avx512_sqrt_ps_512 2351*0fca6ea1SDimitry Andric : Intrinsic::x86_avx512_sqrt_pd_512; 2352*0fca6ea1SDimitry Andric 2353*0fca6ea1SDimitry Andric Value *Args[] = {CI->getArgOperand(0), CI->getArgOperand(3)}; 2354*0fca6ea1SDimitry Andric Rep = Builder.CreateCall(Intrinsic::getDeclaration(CI->getModule(), IID), 2355*0fca6ea1SDimitry Andric Args); 2356*0fca6ea1SDimitry Andric } else { 2357*0fca6ea1SDimitry Andric Rep = Builder.CreateCall(Intrinsic::getDeclaration(F->getParent(), 2358*0fca6ea1SDimitry Andric Intrinsic::sqrt, 2359*0fca6ea1SDimitry Andric CI->getType()), 2360*0fca6ea1SDimitry Andric {CI->getArgOperand(0)}); 2361*0fca6ea1SDimitry Andric } 2362*0fca6ea1SDimitry Andric Rep = 2363*0fca6ea1SDimitry Andric emitX86Select(Builder, CI->getArgOperand(2), Rep, CI->getArgOperand(1)); 2364*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.ptestm") || 2365*0fca6ea1SDimitry Andric Name.starts_with("avx512.ptestnm")) { 2366*0fca6ea1SDimitry Andric Value *Op0 = CI->getArgOperand(0); 2367*0fca6ea1SDimitry Andric Value *Op1 = CI->getArgOperand(1); 2368*0fca6ea1SDimitry Andric Value *Mask = CI->getArgOperand(2); 2369*0fca6ea1SDimitry Andric Rep = Builder.CreateAnd(Op0, Op1); 2370*0fca6ea1SDimitry Andric llvm::Type *Ty = Op0->getType(); 2371*0fca6ea1SDimitry Andric Value *Zero = llvm::Constant::getNullValue(Ty); 2372*0fca6ea1SDimitry Andric ICmpInst::Predicate Pred = Name.starts_with("avx512.ptestm") 2373*0fca6ea1SDimitry Andric ? ICmpInst::ICMP_NE 2374*0fca6ea1SDimitry Andric : ICmpInst::ICMP_EQ; 2375*0fca6ea1SDimitry Andric Rep = Builder.CreateICmp(Pred, Rep, Zero); 2376*0fca6ea1SDimitry Andric Rep = applyX86MaskOn1BitsVec(Builder, Rep, Mask); 2377*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.pbroadcast")) { 2378*0fca6ea1SDimitry Andric unsigned NumElts = cast<FixedVectorType>(CI->getArgOperand(1)->getType()) 2379*0fca6ea1SDimitry Andric ->getNumElements(); 2380*0fca6ea1SDimitry Andric Rep = Builder.CreateVectorSplat(NumElts, CI->getArgOperand(0)); 2381*0fca6ea1SDimitry Andric Rep = 2382*0fca6ea1SDimitry Andric emitX86Select(Builder, CI->getArgOperand(2), Rep, CI->getArgOperand(1)); 2383*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.kunpck")) { 2384*0fca6ea1SDimitry Andric unsigned NumElts = CI->getType()->getScalarSizeInBits(); 2385*0fca6ea1SDimitry Andric Value *LHS = getX86MaskVec(Builder, CI->getArgOperand(0), NumElts); 2386*0fca6ea1SDimitry Andric Value *RHS = getX86MaskVec(Builder, CI->getArgOperand(1), NumElts); 2387*0fca6ea1SDimitry Andric int Indices[64]; 2388*0fca6ea1SDimitry Andric for (unsigned i = 0; i != NumElts; ++i) 2389*0fca6ea1SDimitry Andric Indices[i] = i; 2390*0fca6ea1SDimitry Andric 2391*0fca6ea1SDimitry Andric // First extract half of each vector. This gives better codegen than 2392*0fca6ea1SDimitry Andric // doing it in a single shuffle. 2393*0fca6ea1SDimitry Andric LHS = Builder.CreateShuffleVector(LHS, LHS, ArrayRef(Indices, NumElts / 2)); 2394*0fca6ea1SDimitry Andric RHS = Builder.CreateShuffleVector(RHS, RHS, ArrayRef(Indices, NumElts / 2)); 2395*0fca6ea1SDimitry Andric // Concat the vectors. 2396*0fca6ea1SDimitry Andric // NOTE: Operands have to be swapped to match intrinsic definition. 2397*0fca6ea1SDimitry Andric Rep = Builder.CreateShuffleVector(RHS, LHS, ArrayRef(Indices, NumElts)); 2398*0fca6ea1SDimitry Andric Rep = Builder.CreateBitCast(Rep, CI->getType()); 2399*0fca6ea1SDimitry Andric } else if (Name == "avx512.kand.w") { 2400*0fca6ea1SDimitry Andric Value *LHS = getX86MaskVec(Builder, CI->getArgOperand(0), 16); 2401*0fca6ea1SDimitry Andric Value *RHS = getX86MaskVec(Builder, CI->getArgOperand(1), 16); 2402*0fca6ea1SDimitry Andric Rep = Builder.CreateAnd(LHS, RHS); 2403*0fca6ea1SDimitry Andric Rep = Builder.CreateBitCast(Rep, CI->getType()); 2404*0fca6ea1SDimitry Andric } else if (Name == "avx512.kandn.w") { 2405*0fca6ea1SDimitry Andric Value *LHS = getX86MaskVec(Builder, CI->getArgOperand(0), 16); 2406*0fca6ea1SDimitry Andric Value *RHS = getX86MaskVec(Builder, CI->getArgOperand(1), 16); 2407*0fca6ea1SDimitry Andric LHS = Builder.CreateNot(LHS); 2408*0fca6ea1SDimitry Andric Rep = Builder.CreateAnd(LHS, RHS); 2409*0fca6ea1SDimitry Andric Rep = Builder.CreateBitCast(Rep, CI->getType()); 2410*0fca6ea1SDimitry Andric } else if (Name == "avx512.kor.w") { 2411*0fca6ea1SDimitry Andric Value *LHS = getX86MaskVec(Builder, CI->getArgOperand(0), 16); 2412*0fca6ea1SDimitry Andric Value *RHS = getX86MaskVec(Builder, CI->getArgOperand(1), 16); 2413*0fca6ea1SDimitry Andric Rep = Builder.CreateOr(LHS, RHS); 2414*0fca6ea1SDimitry Andric Rep = Builder.CreateBitCast(Rep, CI->getType()); 2415*0fca6ea1SDimitry Andric } else if (Name == "avx512.kxor.w") { 2416*0fca6ea1SDimitry Andric Value *LHS = getX86MaskVec(Builder, CI->getArgOperand(0), 16); 2417*0fca6ea1SDimitry Andric Value *RHS = getX86MaskVec(Builder, CI->getArgOperand(1), 16); 2418*0fca6ea1SDimitry Andric Rep = Builder.CreateXor(LHS, RHS); 2419*0fca6ea1SDimitry Andric Rep = Builder.CreateBitCast(Rep, CI->getType()); 2420*0fca6ea1SDimitry Andric } else if (Name == "avx512.kxnor.w") { 2421*0fca6ea1SDimitry Andric Value *LHS = getX86MaskVec(Builder, CI->getArgOperand(0), 16); 2422*0fca6ea1SDimitry Andric Value *RHS = getX86MaskVec(Builder, CI->getArgOperand(1), 16); 2423*0fca6ea1SDimitry Andric LHS = Builder.CreateNot(LHS); 2424*0fca6ea1SDimitry Andric Rep = Builder.CreateXor(LHS, RHS); 2425*0fca6ea1SDimitry Andric Rep = Builder.CreateBitCast(Rep, CI->getType()); 2426*0fca6ea1SDimitry Andric } else if (Name == "avx512.knot.w") { 2427*0fca6ea1SDimitry Andric Rep = getX86MaskVec(Builder, CI->getArgOperand(0), 16); 2428*0fca6ea1SDimitry Andric Rep = Builder.CreateNot(Rep); 2429*0fca6ea1SDimitry Andric Rep = Builder.CreateBitCast(Rep, CI->getType()); 2430*0fca6ea1SDimitry Andric } else if (Name == "avx512.kortestz.w" || Name == "avx512.kortestc.w") { 2431*0fca6ea1SDimitry Andric Value *LHS = getX86MaskVec(Builder, CI->getArgOperand(0), 16); 2432*0fca6ea1SDimitry Andric Value *RHS = getX86MaskVec(Builder, CI->getArgOperand(1), 16); 2433*0fca6ea1SDimitry Andric Rep = Builder.CreateOr(LHS, RHS); 2434*0fca6ea1SDimitry Andric Rep = Builder.CreateBitCast(Rep, Builder.getInt16Ty()); 2435*0fca6ea1SDimitry Andric Value *C; 2436*0fca6ea1SDimitry Andric if (Name[14] == 'c') 2437*0fca6ea1SDimitry Andric C = ConstantInt::getAllOnesValue(Builder.getInt16Ty()); 2438*0fca6ea1SDimitry Andric else 2439*0fca6ea1SDimitry Andric C = ConstantInt::getNullValue(Builder.getInt16Ty()); 2440*0fca6ea1SDimitry Andric Rep = Builder.CreateICmpEQ(Rep, C); 2441*0fca6ea1SDimitry Andric Rep = Builder.CreateZExt(Rep, Builder.getInt32Ty()); 2442*0fca6ea1SDimitry Andric } else if (Name == "sse.add.ss" || Name == "sse2.add.sd" || 2443*0fca6ea1SDimitry Andric Name == "sse.sub.ss" || Name == "sse2.sub.sd" || 2444*0fca6ea1SDimitry Andric Name == "sse.mul.ss" || Name == "sse2.mul.sd" || 2445*0fca6ea1SDimitry Andric Name == "sse.div.ss" || Name == "sse2.div.sd") { 2446*0fca6ea1SDimitry Andric Type *I32Ty = Type::getInt32Ty(C); 2447*0fca6ea1SDimitry Andric Value *Elt0 = Builder.CreateExtractElement(CI->getArgOperand(0), 2448*0fca6ea1SDimitry Andric ConstantInt::get(I32Ty, 0)); 2449*0fca6ea1SDimitry Andric Value *Elt1 = Builder.CreateExtractElement(CI->getArgOperand(1), 2450*0fca6ea1SDimitry Andric ConstantInt::get(I32Ty, 0)); 2451*0fca6ea1SDimitry Andric Value *EltOp; 2452*0fca6ea1SDimitry Andric if (Name.contains(".add.")) 2453*0fca6ea1SDimitry Andric EltOp = Builder.CreateFAdd(Elt0, Elt1); 2454*0fca6ea1SDimitry Andric else if (Name.contains(".sub.")) 2455*0fca6ea1SDimitry Andric EltOp = Builder.CreateFSub(Elt0, Elt1); 2456*0fca6ea1SDimitry Andric else if (Name.contains(".mul.")) 2457*0fca6ea1SDimitry Andric EltOp = Builder.CreateFMul(Elt0, Elt1); 2458*0fca6ea1SDimitry Andric else 2459*0fca6ea1SDimitry Andric EltOp = Builder.CreateFDiv(Elt0, Elt1); 2460*0fca6ea1SDimitry Andric Rep = Builder.CreateInsertElement(CI->getArgOperand(0), EltOp, 2461*0fca6ea1SDimitry Andric ConstantInt::get(I32Ty, 0)); 2462*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.pcmp")) { 2463*0fca6ea1SDimitry Andric // "avx512.mask.pcmpeq." or "avx512.mask.pcmpgt." 2464*0fca6ea1SDimitry Andric bool CmpEq = Name[16] == 'e'; 2465*0fca6ea1SDimitry Andric Rep = upgradeMaskedCompare(Builder, *CI, CmpEq ? 0 : 6, true); 2466*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.vpshufbitqmb.")) { 2467*0fca6ea1SDimitry Andric Type *OpTy = CI->getArgOperand(0)->getType(); 2468*0fca6ea1SDimitry Andric unsigned VecWidth = OpTy->getPrimitiveSizeInBits(); 2469*0fca6ea1SDimitry Andric Intrinsic::ID IID; 2470*0fca6ea1SDimitry Andric switch (VecWidth) { 2471*0fca6ea1SDimitry Andric default: 2472*0fca6ea1SDimitry Andric llvm_unreachable("Unexpected intrinsic"); 2473*0fca6ea1SDimitry Andric case 128: 2474*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_vpshufbitqmb_128; 2475*0fca6ea1SDimitry Andric break; 2476*0fca6ea1SDimitry Andric case 256: 2477*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_vpshufbitqmb_256; 2478*0fca6ea1SDimitry Andric break; 2479*0fca6ea1SDimitry Andric case 512: 2480*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_vpshufbitqmb_512; 2481*0fca6ea1SDimitry Andric break; 2482*0fca6ea1SDimitry Andric } 2483*0fca6ea1SDimitry Andric 2484*0fca6ea1SDimitry Andric Rep = Builder.CreateCall(Intrinsic::getDeclaration(F->getParent(), IID), 2485*0fca6ea1SDimitry Andric {CI->getOperand(0), CI->getArgOperand(1)}); 2486*0fca6ea1SDimitry Andric Rep = applyX86MaskOn1BitsVec(Builder, Rep, CI->getArgOperand(2)); 2487*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.fpclass.p")) { 2488*0fca6ea1SDimitry Andric Type *OpTy = CI->getArgOperand(0)->getType(); 2489*0fca6ea1SDimitry Andric unsigned VecWidth = OpTy->getPrimitiveSizeInBits(); 2490*0fca6ea1SDimitry Andric unsigned EltWidth = OpTy->getScalarSizeInBits(); 2491*0fca6ea1SDimitry Andric Intrinsic::ID IID; 2492*0fca6ea1SDimitry Andric if (VecWidth == 128 && EltWidth == 32) 2493*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_fpclass_ps_128; 2494*0fca6ea1SDimitry Andric else if (VecWidth == 256 && EltWidth == 32) 2495*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_fpclass_ps_256; 2496*0fca6ea1SDimitry Andric else if (VecWidth == 512 && EltWidth == 32) 2497*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_fpclass_ps_512; 2498*0fca6ea1SDimitry Andric else if (VecWidth == 128 && EltWidth == 64) 2499*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_fpclass_pd_128; 2500*0fca6ea1SDimitry Andric else if (VecWidth == 256 && EltWidth == 64) 2501*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_fpclass_pd_256; 2502*0fca6ea1SDimitry Andric else if (VecWidth == 512 && EltWidth == 64) 2503*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_fpclass_pd_512; 2504*0fca6ea1SDimitry Andric else 2505*0fca6ea1SDimitry Andric llvm_unreachable("Unexpected intrinsic"); 2506*0fca6ea1SDimitry Andric 2507*0fca6ea1SDimitry Andric Rep = Builder.CreateCall(Intrinsic::getDeclaration(F->getParent(), IID), 2508*0fca6ea1SDimitry Andric {CI->getOperand(0), CI->getArgOperand(1)}); 2509*0fca6ea1SDimitry Andric Rep = applyX86MaskOn1BitsVec(Builder, Rep, CI->getArgOperand(2)); 2510*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.cmp.p")) { 2511*0fca6ea1SDimitry Andric SmallVector<Value *, 4> Args(CI->args()); 2512*0fca6ea1SDimitry Andric Type *OpTy = Args[0]->getType(); 2513*0fca6ea1SDimitry Andric unsigned VecWidth = OpTy->getPrimitiveSizeInBits(); 2514*0fca6ea1SDimitry Andric unsigned EltWidth = OpTy->getScalarSizeInBits(); 2515*0fca6ea1SDimitry Andric Intrinsic::ID IID; 2516*0fca6ea1SDimitry Andric if (VecWidth == 128 && EltWidth == 32) 2517*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_mask_cmp_ps_128; 2518*0fca6ea1SDimitry Andric else if (VecWidth == 256 && EltWidth == 32) 2519*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_mask_cmp_ps_256; 2520*0fca6ea1SDimitry Andric else if (VecWidth == 512 && EltWidth == 32) 2521*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_mask_cmp_ps_512; 2522*0fca6ea1SDimitry Andric else if (VecWidth == 128 && EltWidth == 64) 2523*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_mask_cmp_pd_128; 2524*0fca6ea1SDimitry Andric else if (VecWidth == 256 && EltWidth == 64) 2525*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_mask_cmp_pd_256; 2526*0fca6ea1SDimitry Andric else if (VecWidth == 512 && EltWidth == 64) 2527*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_mask_cmp_pd_512; 2528*0fca6ea1SDimitry Andric else 2529*0fca6ea1SDimitry Andric llvm_unreachable("Unexpected intrinsic"); 2530*0fca6ea1SDimitry Andric 2531*0fca6ea1SDimitry Andric Value *Mask = Constant::getAllOnesValue(CI->getType()); 2532*0fca6ea1SDimitry Andric if (VecWidth == 512) 2533*0fca6ea1SDimitry Andric std::swap(Mask, Args.back()); 2534*0fca6ea1SDimitry Andric Args.push_back(Mask); 2535*0fca6ea1SDimitry Andric 2536*0fca6ea1SDimitry Andric Rep = Builder.CreateCall(Intrinsic::getDeclaration(F->getParent(), IID), 2537*0fca6ea1SDimitry Andric Args); 2538*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.cmp.")) { 2539*0fca6ea1SDimitry Andric // Integer compare intrinsics. 2540*0fca6ea1SDimitry Andric unsigned Imm = cast<ConstantInt>(CI->getArgOperand(2))->getZExtValue(); 2541*0fca6ea1SDimitry Andric Rep = upgradeMaskedCompare(Builder, *CI, Imm, true); 2542*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.ucmp.")) { 2543*0fca6ea1SDimitry Andric unsigned Imm = cast<ConstantInt>(CI->getArgOperand(2))->getZExtValue(); 2544*0fca6ea1SDimitry Andric Rep = upgradeMaskedCompare(Builder, *CI, Imm, false); 2545*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.cvtb2mask.") || 2546*0fca6ea1SDimitry Andric Name.starts_with("avx512.cvtw2mask.") || 2547*0fca6ea1SDimitry Andric Name.starts_with("avx512.cvtd2mask.") || 2548*0fca6ea1SDimitry Andric Name.starts_with("avx512.cvtq2mask.")) { 2549*0fca6ea1SDimitry Andric Value *Op = CI->getArgOperand(0); 2550*0fca6ea1SDimitry Andric Value *Zero = llvm::Constant::getNullValue(Op->getType()); 2551*0fca6ea1SDimitry Andric Rep = Builder.CreateICmp(ICmpInst::ICMP_SLT, Op, Zero); 2552*0fca6ea1SDimitry Andric Rep = applyX86MaskOn1BitsVec(Builder, Rep, nullptr); 2553*0fca6ea1SDimitry Andric } else if (Name == "ssse3.pabs.b.128" || Name == "ssse3.pabs.w.128" || 2554*0fca6ea1SDimitry Andric Name == "ssse3.pabs.d.128" || Name.starts_with("avx2.pabs") || 2555*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.pabs")) { 2556*0fca6ea1SDimitry Andric Rep = upgradeAbs(Builder, *CI); 2557*0fca6ea1SDimitry Andric } else if (Name == "sse41.pmaxsb" || Name == "sse2.pmaxs.w" || 2558*0fca6ea1SDimitry Andric Name == "sse41.pmaxsd" || Name.starts_with("avx2.pmaxs") || 2559*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.pmaxs")) { 2560*0fca6ea1SDimitry Andric Rep = upgradeX86BinaryIntrinsics(Builder, *CI, Intrinsic::smax); 2561*0fca6ea1SDimitry Andric } else if (Name == "sse2.pmaxu.b" || Name == "sse41.pmaxuw" || 2562*0fca6ea1SDimitry Andric Name == "sse41.pmaxud" || Name.starts_with("avx2.pmaxu") || 2563*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.pmaxu")) { 2564*0fca6ea1SDimitry Andric Rep = upgradeX86BinaryIntrinsics(Builder, *CI, Intrinsic::umax); 2565*0fca6ea1SDimitry Andric } else if (Name == "sse41.pminsb" || Name == "sse2.pmins.w" || 2566*0fca6ea1SDimitry Andric Name == "sse41.pminsd" || Name.starts_with("avx2.pmins") || 2567*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.pmins")) { 2568*0fca6ea1SDimitry Andric Rep = upgradeX86BinaryIntrinsics(Builder, *CI, Intrinsic::smin); 2569*0fca6ea1SDimitry Andric } else if (Name == "sse2.pminu.b" || Name == "sse41.pminuw" || 2570*0fca6ea1SDimitry Andric Name == "sse41.pminud" || Name.starts_with("avx2.pminu") || 2571*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.pminu")) { 2572*0fca6ea1SDimitry Andric Rep = upgradeX86BinaryIntrinsics(Builder, *CI, Intrinsic::umin); 2573*0fca6ea1SDimitry Andric } else if (Name == "sse2.pmulu.dq" || Name == "avx2.pmulu.dq" || 2574*0fca6ea1SDimitry Andric Name == "avx512.pmulu.dq.512" || 2575*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.pmulu.dq.")) { 2576*0fca6ea1SDimitry Andric Rep = upgradePMULDQ(Builder, *CI, /*Signed*/ false); 2577*0fca6ea1SDimitry Andric } else if (Name == "sse41.pmuldq" || Name == "avx2.pmul.dq" || 2578*0fca6ea1SDimitry Andric Name == "avx512.pmul.dq.512" || 2579*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.pmul.dq.")) { 2580*0fca6ea1SDimitry Andric Rep = upgradePMULDQ(Builder, *CI, /*Signed*/ true); 2581*0fca6ea1SDimitry Andric } else if (Name == "sse.cvtsi2ss" || Name == "sse2.cvtsi2sd" || 2582*0fca6ea1SDimitry Andric Name == "sse.cvtsi642ss" || Name == "sse2.cvtsi642sd") { 2583*0fca6ea1SDimitry Andric Rep = 2584*0fca6ea1SDimitry Andric Builder.CreateSIToFP(CI->getArgOperand(1), 2585*0fca6ea1SDimitry Andric cast<VectorType>(CI->getType())->getElementType()); 2586*0fca6ea1SDimitry Andric Rep = Builder.CreateInsertElement(CI->getArgOperand(0), Rep, (uint64_t)0); 2587*0fca6ea1SDimitry Andric } else if (Name == "avx512.cvtusi2sd") { 2588*0fca6ea1SDimitry Andric Rep = 2589*0fca6ea1SDimitry Andric Builder.CreateUIToFP(CI->getArgOperand(1), 2590*0fca6ea1SDimitry Andric cast<VectorType>(CI->getType())->getElementType()); 2591*0fca6ea1SDimitry Andric Rep = Builder.CreateInsertElement(CI->getArgOperand(0), Rep, (uint64_t)0); 2592*0fca6ea1SDimitry Andric } else if (Name == "sse2.cvtss2sd") { 2593*0fca6ea1SDimitry Andric Rep = Builder.CreateExtractElement(CI->getArgOperand(1), (uint64_t)0); 2594*0fca6ea1SDimitry Andric Rep = Builder.CreateFPExt( 2595*0fca6ea1SDimitry Andric Rep, cast<VectorType>(CI->getType())->getElementType()); 2596*0fca6ea1SDimitry Andric Rep = Builder.CreateInsertElement(CI->getArgOperand(0), Rep, (uint64_t)0); 2597*0fca6ea1SDimitry Andric } else if (Name == "sse2.cvtdq2pd" || Name == "sse2.cvtdq2ps" || 2598*0fca6ea1SDimitry Andric Name == "avx.cvtdq2.pd.256" || Name == "avx.cvtdq2.ps.256" || 2599*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.cvtdq2pd.") || 2600*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.cvtudq2pd.") || 2601*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.cvtdq2ps.") || 2602*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.cvtudq2ps.") || 2603*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.cvtqq2pd.") || 2604*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.cvtuqq2pd.") || 2605*0fca6ea1SDimitry Andric Name == "avx512.mask.cvtqq2ps.256" || 2606*0fca6ea1SDimitry Andric Name == "avx512.mask.cvtqq2ps.512" || 2607*0fca6ea1SDimitry Andric Name == "avx512.mask.cvtuqq2ps.256" || 2608*0fca6ea1SDimitry Andric Name == "avx512.mask.cvtuqq2ps.512" || Name == "sse2.cvtps2pd" || 2609*0fca6ea1SDimitry Andric Name == "avx.cvt.ps2.pd.256" || 2610*0fca6ea1SDimitry Andric Name == "avx512.mask.cvtps2pd.128" || 2611*0fca6ea1SDimitry Andric Name == "avx512.mask.cvtps2pd.256") { 2612*0fca6ea1SDimitry Andric auto *DstTy = cast<FixedVectorType>(CI->getType()); 2613*0fca6ea1SDimitry Andric Rep = CI->getArgOperand(0); 2614*0fca6ea1SDimitry Andric auto *SrcTy = cast<FixedVectorType>(Rep->getType()); 2615*0fca6ea1SDimitry Andric 2616*0fca6ea1SDimitry Andric unsigned NumDstElts = DstTy->getNumElements(); 2617*0fca6ea1SDimitry Andric if (NumDstElts < SrcTy->getNumElements()) { 2618*0fca6ea1SDimitry Andric assert(NumDstElts == 2 && "Unexpected vector size"); 2619*0fca6ea1SDimitry Andric Rep = Builder.CreateShuffleVector(Rep, Rep, ArrayRef<int>{0, 1}); 2620*0fca6ea1SDimitry Andric } 2621*0fca6ea1SDimitry Andric 2622*0fca6ea1SDimitry Andric bool IsPS2PD = SrcTy->getElementType()->isFloatTy(); 2623*0fca6ea1SDimitry Andric bool IsUnsigned = Name.contains("cvtu"); 2624*0fca6ea1SDimitry Andric if (IsPS2PD) 2625*0fca6ea1SDimitry Andric Rep = Builder.CreateFPExt(Rep, DstTy, "cvtps2pd"); 2626*0fca6ea1SDimitry Andric else if (CI->arg_size() == 4 && 2627*0fca6ea1SDimitry Andric (!isa<ConstantInt>(CI->getArgOperand(3)) || 2628*0fca6ea1SDimitry Andric cast<ConstantInt>(CI->getArgOperand(3))->getZExtValue() != 4)) { 2629*0fca6ea1SDimitry Andric Intrinsic::ID IID = IsUnsigned ? Intrinsic::x86_avx512_uitofp_round 2630*0fca6ea1SDimitry Andric : Intrinsic::x86_avx512_sitofp_round; 2631*0fca6ea1SDimitry Andric Function *F = 2632*0fca6ea1SDimitry Andric Intrinsic::getDeclaration(CI->getModule(), IID, {DstTy, SrcTy}); 2633*0fca6ea1SDimitry Andric Rep = Builder.CreateCall(F, {Rep, CI->getArgOperand(3)}); 2634*0fca6ea1SDimitry Andric } else { 2635*0fca6ea1SDimitry Andric Rep = IsUnsigned ? Builder.CreateUIToFP(Rep, DstTy, "cvt") 2636*0fca6ea1SDimitry Andric : Builder.CreateSIToFP(Rep, DstTy, "cvt"); 2637*0fca6ea1SDimitry Andric } 2638*0fca6ea1SDimitry Andric 2639*0fca6ea1SDimitry Andric if (CI->arg_size() >= 3) 2640*0fca6ea1SDimitry Andric Rep = emitX86Select(Builder, CI->getArgOperand(2), Rep, 2641*0fca6ea1SDimitry Andric CI->getArgOperand(1)); 2642*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.vcvtph2ps.") || 2643*0fca6ea1SDimitry Andric Name.starts_with("vcvtph2ps.")) { 2644*0fca6ea1SDimitry Andric auto *DstTy = cast<FixedVectorType>(CI->getType()); 2645*0fca6ea1SDimitry Andric Rep = CI->getArgOperand(0); 2646*0fca6ea1SDimitry Andric auto *SrcTy = cast<FixedVectorType>(Rep->getType()); 2647*0fca6ea1SDimitry Andric unsigned NumDstElts = DstTy->getNumElements(); 2648*0fca6ea1SDimitry Andric if (NumDstElts != SrcTy->getNumElements()) { 2649*0fca6ea1SDimitry Andric assert(NumDstElts == 4 && "Unexpected vector size"); 2650*0fca6ea1SDimitry Andric Rep = Builder.CreateShuffleVector(Rep, Rep, ArrayRef<int>{0, 1, 2, 3}); 2651*0fca6ea1SDimitry Andric } 2652*0fca6ea1SDimitry Andric Rep = Builder.CreateBitCast( 2653*0fca6ea1SDimitry Andric Rep, FixedVectorType::get(Type::getHalfTy(C), NumDstElts)); 2654*0fca6ea1SDimitry Andric Rep = Builder.CreateFPExt(Rep, DstTy, "cvtph2ps"); 2655*0fca6ea1SDimitry Andric if (CI->arg_size() >= 3) 2656*0fca6ea1SDimitry Andric Rep = emitX86Select(Builder, CI->getArgOperand(2), Rep, 2657*0fca6ea1SDimitry Andric CI->getArgOperand(1)); 2658*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.load")) { 2659*0fca6ea1SDimitry Andric // "avx512.mask.loadu." or "avx512.mask.load." 2660*0fca6ea1SDimitry Andric bool Aligned = Name[16] != 'u'; // "avx512.mask.loadu". 2661*0fca6ea1SDimitry Andric Rep = upgradeMaskedLoad(Builder, CI->getArgOperand(0), CI->getArgOperand(1), 2662*0fca6ea1SDimitry Andric CI->getArgOperand(2), Aligned); 2663*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.expand.load.")) { 2664*0fca6ea1SDimitry Andric auto *ResultTy = cast<FixedVectorType>(CI->getType()); 2665*0fca6ea1SDimitry Andric Type *PtrTy = ResultTy->getElementType(); 2666*0fca6ea1SDimitry Andric 2667*0fca6ea1SDimitry Andric // Cast the pointer to element type. 2668*0fca6ea1SDimitry Andric Value *Ptr = Builder.CreateBitCast(CI->getOperand(0), 2669*0fca6ea1SDimitry Andric llvm::PointerType::getUnqual(PtrTy)); 2670*0fca6ea1SDimitry Andric 2671*0fca6ea1SDimitry Andric Value *MaskVec = getX86MaskVec(Builder, CI->getArgOperand(2), 2672*0fca6ea1SDimitry Andric ResultTy->getNumElements()); 2673*0fca6ea1SDimitry Andric 2674*0fca6ea1SDimitry Andric Function *ELd = Intrinsic::getDeclaration( 2675*0fca6ea1SDimitry Andric F->getParent(), Intrinsic::masked_expandload, ResultTy); 2676*0fca6ea1SDimitry Andric Rep = Builder.CreateCall(ELd, {Ptr, MaskVec, CI->getOperand(1)}); 2677*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.compress.store.")) { 2678*0fca6ea1SDimitry Andric auto *ResultTy = cast<VectorType>(CI->getArgOperand(1)->getType()); 2679*0fca6ea1SDimitry Andric Type *PtrTy = ResultTy->getElementType(); 2680*0fca6ea1SDimitry Andric 2681*0fca6ea1SDimitry Andric // Cast the pointer to element type. 2682*0fca6ea1SDimitry Andric Value *Ptr = Builder.CreateBitCast(CI->getOperand(0), 2683*0fca6ea1SDimitry Andric llvm::PointerType::getUnqual(PtrTy)); 2684*0fca6ea1SDimitry Andric 2685*0fca6ea1SDimitry Andric Value *MaskVec = 2686*0fca6ea1SDimitry Andric getX86MaskVec(Builder, CI->getArgOperand(2), 2687*0fca6ea1SDimitry Andric cast<FixedVectorType>(ResultTy)->getNumElements()); 2688*0fca6ea1SDimitry Andric 2689*0fca6ea1SDimitry Andric Function *CSt = Intrinsic::getDeclaration( 2690*0fca6ea1SDimitry Andric F->getParent(), Intrinsic::masked_compressstore, ResultTy); 2691*0fca6ea1SDimitry Andric Rep = Builder.CreateCall(CSt, {CI->getArgOperand(1), Ptr, MaskVec}); 2692*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.compress.") || 2693*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.expand.")) { 2694*0fca6ea1SDimitry Andric auto *ResultTy = cast<FixedVectorType>(CI->getType()); 2695*0fca6ea1SDimitry Andric 2696*0fca6ea1SDimitry Andric Value *MaskVec = getX86MaskVec(Builder, CI->getArgOperand(2), 2697*0fca6ea1SDimitry Andric ResultTy->getNumElements()); 2698*0fca6ea1SDimitry Andric 2699*0fca6ea1SDimitry Andric bool IsCompress = Name[12] == 'c'; 2700*0fca6ea1SDimitry Andric Intrinsic::ID IID = IsCompress ? Intrinsic::x86_avx512_mask_compress 2701*0fca6ea1SDimitry Andric : Intrinsic::x86_avx512_mask_expand; 2702*0fca6ea1SDimitry Andric Function *Intr = Intrinsic::getDeclaration(F->getParent(), IID, ResultTy); 2703*0fca6ea1SDimitry Andric Rep = Builder.CreateCall(Intr, 2704*0fca6ea1SDimitry Andric {CI->getOperand(0), CI->getOperand(1), MaskVec}); 2705*0fca6ea1SDimitry Andric } else if (Name.starts_with("xop.vpcom")) { 2706*0fca6ea1SDimitry Andric bool IsSigned; 2707*0fca6ea1SDimitry Andric if (Name.ends_with("ub") || Name.ends_with("uw") || Name.ends_with("ud") || 2708*0fca6ea1SDimitry Andric Name.ends_with("uq")) 2709*0fca6ea1SDimitry Andric IsSigned = false; 2710*0fca6ea1SDimitry Andric else if (Name.ends_with("b") || Name.ends_with("w") || 2711*0fca6ea1SDimitry Andric Name.ends_with("d") || Name.ends_with("q")) 2712*0fca6ea1SDimitry Andric IsSigned = true; 2713*0fca6ea1SDimitry Andric else 2714*0fca6ea1SDimitry Andric llvm_unreachable("Unknown suffix"); 2715*0fca6ea1SDimitry Andric 2716*0fca6ea1SDimitry Andric unsigned Imm; 2717*0fca6ea1SDimitry Andric if (CI->arg_size() == 3) { 2718*0fca6ea1SDimitry Andric Imm = cast<ConstantInt>(CI->getArgOperand(2))->getZExtValue(); 2719*0fca6ea1SDimitry Andric } else { 2720*0fca6ea1SDimitry Andric Name = Name.substr(9); // strip off "xop.vpcom" 2721*0fca6ea1SDimitry Andric if (Name.starts_with("lt")) 2722*0fca6ea1SDimitry Andric Imm = 0; 2723*0fca6ea1SDimitry Andric else if (Name.starts_with("le")) 2724*0fca6ea1SDimitry Andric Imm = 1; 2725*0fca6ea1SDimitry Andric else if (Name.starts_with("gt")) 2726*0fca6ea1SDimitry Andric Imm = 2; 2727*0fca6ea1SDimitry Andric else if (Name.starts_with("ge")) 2728*0fca6ea1SDimitry Andric Imm = 3; 2729*0fca6ea1SDimitry Andric else if (Name.starts_with("eq")) 2730*0fca6ea1SDimitry Andric Imm = 4; 2731*0fca6ea1SDimitry Andric else if (Name.starts_with("ne")) 2732*0fca6ea1SDimitry Andric Imm = 5; 2733*0fca6ea1SDimitry Andric else if (Name.starts_with("false")) 2734*0fca6ea1SDimitry Andric Imm = 6; 2735*0fca6ea1SDimitry Andric else if (Name.starts_with("true")) 2736*0fca6ea1SDimitry Andric Imm = 7; 2737*0fca6ea1SDimitry Andric else 2738*0fca6ea1SDimitry Andric llvm_unreachable("Unknown condition"); 2739*0fca6ea1SDimitry Andric } 2740*0fca6ea1SDimitry Andric 2741*0fca6ea1SDimitry Andric Rep = upgradeX86vpcom(Builder, *CI, Imm, IsSigned); 2742*0fca6ea1SDimitry Andric } else if (Name.starts_with("xop.vpcmov")) { 2743*0fca6ea1SDimitry Andric Value *Sel = CI->getArgOperand(2); 2744*0fca6ea1SDimitry Andric Value *NotSel = Builder.CreateNot(Sel); 2745*0fca6ea1SDimitry Andric Value *Sel0 = Builder.CreateAnd(CI->getArgOperand(0), Sel); 2746*0fca6ea1SDimitry Andric Value *Sel1 = Builder.CreateAnd(CI->getArgOperand(1), NotSel); 2747*0fca6ea1SDimitry Andric Rep = Builder.CreateOr(Sel0, Sel1); 2748*0fca6ea1SDimitry Andric } else if (Name.starts_with("xop.vprot") || Name.starts_with("avx512.prol") || 2749*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.prol")) { 2750*0fca6ea1SDimitry Andric Rep = upgradeX86Rotate(Builder, *CI, false); 2751*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.pror") || 2752*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.pror")) { 2753*0fca6ea1SDimitry Andric Rep = upgradeX86Rotate(Builder, *CI, true); 2754*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.vpshld.") || 2755*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.vpshld") || 2756*0fca6ea1SDimitry Andric Name.starts_with("avx512.maskz.vpshld")) { 2757*0fca6ea1SDimitry Andric bool ZeroMask = Name[11] == 'z'; 2758*0fca6ea1SDimitry Andric Rep = upgradeX86ConcatShift(Builder, *CI, false, ZeroMask); 2759*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.vpshrd.") || 2760*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.vpshrd") || 2761*0fca6ea1SDimitry Andric Name.starts_with("avx512.maskz.vpshrd")) { 2762*0fca6ea1SDimitry Andric bool ZeroMask = Name[11] == 'z'; 2763*0fca6ea1SDimitry Andric Rep = upgradeX86ConcatShift(Builder, *CI, true, ZeroMask); 2764*0fca6ea1SDimitry Andric } else if (Name == "sse42.crc32.64.8") { 2765*0fca6ea1SDimitry Andric Function *CRC32 = Intrinsic::getDeclaration( 2766*0fca6ea1SDimitry Andric F->getParent(), Intrinsic::x86_sse42_crc32_32_8); 2767*0fca6ea1SDimitry Andric Value *Trunc0 = 2768*0fca6ea1SDimitry Andric Builder.CreateTrunc(CI->getArgOperand(0), Type::getInt32Ty(C)); 2769*0fca6ea1SDimitry Andric Rep = Builder.CreateCall(CRC32, {Trunc0, CI->getArgOperand(1)}); 2770*0fca6ea1SDimitry Andric Rep = Builder.CreateZExt(Rep, CI->getType(), ""); 2771*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx.vbroadcast.s") || 2772*0fca6ea1SDimitry Andric Name.starts_with("avx512.vbroadcast.s")) { 2773*0fca6ea1SDimitry Andric // Replace broadcasts with a series of insertelements. 2774*0fca6ea1SDimitry Andric auto *VecTy = cast<FixedVectorType>(CI->getType()); 2775*0fca6ea1SDimitry Andric Type *EltTy = VecTy->getElementType(); 2776*0fca6ea1SDimitry Andric unsigned EltNum = VecTy->getNumElements(); 2777*0fca6ea1SDimitry Andric Value *Load = Builder.CreateLoad(EltTy, CI->getArgOperand(0)); 2778*0fca6ea1SDimitry Andric Type *I32Ty = Type::getInt32Ty(C); 2779*0fca6ea1SDimitry Andric Rep = PoisonValue::get(VecTy); 2780*0fca6ea1SDimitry Andric for (unsigned I = 0; I < EltNum; ++I) 2781*0fca6ea1SDimitry Andric Rep = Builder.CreateInsertElement(Rep, Load, ConstantInt::get(I32Ty, I)); 2782*0fca6ea1SDimitry Andric } else if (Name.starts_with("sse41.pmovsx") || 2783*0fca6ea1SDimitry Andric Name.starts_with("sse41.pmovzx") || 2784*0fca6ea1SDimitry Andric Name.starts_with("avx2.pmovsx") || 2785*0fca6ea1SDimitry Andric Name.starts_with("avx2.pmovzx") || 2786*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.pmovsx") || 2787*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.pmovzx")) { 2788*0fca6ea1SDimitry Andric auto *DstTy = cast<FixedVectorType>(CI->getType()); 2789*0fca6ea1SDimitry Andric unsigned NumDstElts = DstTy->getNumElements(); 2790*0fca6ea1SDimitry Andric 2791*0fca6ea1SDimitry Andric // Extract a subvector of the first NumDstElts lanes and sign/zero extend. 2792*0fca6ea1SDimitry Andric SmallVector<int, 8> ShuffleMask(NumDstElts); 2793*0fca6ea1SDimitry Andric for (unsigned i = 0; i != NumDstElts; ++i) 2794*0fca6ea1SDimitry Andric ShuffleMask[i] = i; 2795*0fca6ea1SDimitry Andric 2796*0fca6ea1SDimitry Andric Value *SV = Builder.CreateShuffleVector(CI->getArgOperand(0), ShuffleMask); 2797*0fca6ea1SDimitry Andric 2798*0fca6ea1SDimitry Andric bool DoSext = Name.contains("pmovsx"); 2799*0fca6ea1SDimitry Andric Rep = 2800*0fca6ea1SDimitry Andric DoSext ? Builder.CreateSExt(SV, DstTy) : Builder.CreateZExt(SV, DstTy); 2801*0fca6ea1SDimitry Andric // If there are 3 arguments, it's a masked intrinsic so we need a select. 2802*0fca6ea1SDimitry Andric if (CI->arg_size() == 3) 2803*0fca6ea1SDimitry Andric Rep = emitX86Select(Builder, CI->getArgOperand(2), Rep, 2804*0fca6ea1SDimitry Andric CI->getArgOperand(1)); 2805*0fca6ea1SDimitry Andric } else if (Name == "avx512.mask.pmov.qd.256" || 2806*0fca6ea1SDimitry Andric Name == "avx512.mask.pmov.qd.512" || 2807*0fca6ea1SDimitry Andric Name == "avx512.mask.pmov.wb.256" || 2808*0fca6ea1SDimitry Andric Name == "avx512.mask.pmov.wb.512") { 2809*0fca6ea1SDimitry Andric Type *Ty = CI->getArgOperand(1)->getType(); 2810*0fca6ea1SDimitry Andric Rep = Builder.CreateTrunc(CI->getArgOperand(0), Ty); 2811*0fca6ea1SDimitry Andric Rep = 2812*0fca6ea1SDimitry Andric emitX86Select(Builder, CI->getArgOperand(2), Rep, CI->getArgOperand(1)); 2813*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx.vbroadcastf128") || 2814*0fca6ea1SDimitry Andric Name == "avx2.vbroadcasti128") { 2815*0fca6ea1SDimitry Andric // Replace vbroadcastf128/vbroadcasti128 with a vector load+shuffle. 2816*0fca6ea1SDimitry Andric Type *EltTy = cast<VectorType>(CI->getType())->getElementType(); 2817*0fca6ea1SDimitry Andric unsigned NumSrcElts = 128 / EltTy->getPrimitiveSizeInBits(); 2818*0fca6ea1SDimitry Andric auto *VT = FixedVectorType::get(EltTy, NumSrcElts); 2819*0fca6ea1SDimitry Andric Value *Op = Builder.CreatePointerCast(CI->getArgOperand(0), 2820*0fca6ea1SDimitry Andric PointerType::getUnqual(VT)); 2821*0fca6ea1SDimitry Andric Value *Load = Builder.CreateAlignedLoad(VT, Op, Align(1)); 2822*0fca6ea1SDimitry Andric if (NumSrcElts == 2) 2823*0fca6ea1SDimitry Andric Rep = Builder.CreateShuffleVector(Load, ArrayRef<int>{0, 1, 0, 1}); 2824*0fca6ea1SDimitry Andric else 2825*0fca6ea1SDimitry Andric Rep = Builder.CreateShuffleVector(Load, 2826*0fca6ea1SDimitry Andric ArrayRef<int>{0, 1, 2, 3, 0, 1, 2, 3}); 2827*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.shuf.i") || 2828*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.shuf.f")) { 2829*0fca6ea1SDimitry Andric unsigned Imm = cast<ConstantInt>(CI->getArgOperand(2))->getZExtValue(); 2830*0fca6ea1SDimitry Andric Type *VT = CI->getType(); 2831*0fca6ea1SDimitry Andric unsigned NumLanes = VT->getPrimitiveSizeInBits() / 128; 2832*0fca6ea1SDimitry Andric unsigned NumElementsInLane = 128 / VT->getScalarSizeInBits(); 2833*0fca6ea1SDimitry Andric unsigned ControlBitsMask = NumLanes - 1; 2834*0fca6ea1SDimitry Andric unsigned NumControlBits = NumLanes / 2; 2835*0fca6ea1SDimitry Andric SmallVector<int, 8> ShuffleMask(0); 2836*0fca6ea1SDimitry Andric 2837*0fca6ea1SDimitry Andric for (unsigned l = 0; l != NumLanes; ++l) { 2838*0fca6ea1SDimitry Andric unsigned LaneMask = (Imm >> (l * NumControlBits)) & ControlBitsMask; 2839*0fca6ea1SDimitry Andric // We actually need the other source. 2840*0fca6ea1SDimitry Andric if (l >= NumLanes / 2) 2841*0fca6ea1SDimitry Andric LaneMask += NumLanes; 2842*0fca6ea1SDimitry Andric for (unsigned i = 0; i != NumElementsInLane; ++i) 2843*0fca6ea1SDimitry Andric ShuffleMask.push_back(LaneMask * NumElementsInLane + i); 2844*0fca6ea1SDimitry Andric } 2845*0fca6ea1SDimitry Andric Rep = Builder.CreateShuffleVector(CI->getArgOperand(0), 2846*0fca6ea1SDimitry Andric CI->getArgOperand(1), ShuffleMask); 2847*0fca6ea1SDimitry Andric Rep = 2848*0fca6ea1SDimitry Andric emitX86Select(Builder, CI->getArgOperand(4), Rep, CI->getArgOperand(3)); 2849*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.broadcastf") || 2850*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.broadcasti")) { 2851*0fca6ea1SDimitry Andric unsigned NumSrcElts = cast<FixedVectorType>(CI->getArgOperand(0)->getType()) 2852*0fca6ea1SDimitry Andric ->getNumElements(); 2853*0fca6ea1SDimitry Andric unsigned NumDstElts = 2854*0fca6ea1SDimitry Andric cast<FixedVectorType>(CI->getType())->getNumElements(); 2855*0fca6ea1SDimitry Andric 2856*0fca6ea1SDimitry Andric SmallVector<int, 8> ShuffleMask(NumDstElts); 2857*0fca6ea1SDimitry Andric for (unsigned i = 0; i != NumDstElts; ++i) 2858*0fca6ea1SDimitry Andric ShuffleMask[i] = i % NumSrcElts; 2859*0fca6ea1SDimitry Andric 2860*0fca6ea1SDimitry Andric Rep = Builder.CreateShuffleVector(CI->getArgOperand(0), 2861*0fca6ea1SDimitry Andric CI->getArgOperand(0), ShuffleMask); 2862*0fca6ea1SDimitry Andric Rep = 2863*0fca6ea1SDimitry Andric emitX86Select(Builder, CI->getArgOperand(2), Rep, CI->getArgOperand(1)); 2864*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx2.pbroadcast") || 2865*0fca6ea1SDimitry Andric Name.starts_with("avx2.vbroadcast") || 2866*0fca6ea1SDimitry Andric Name.starts_with("avx512.pbroadcast") || 2867*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.broadcast.s")) { 2868*0fca6ea1SDimitry Andric // Replace vp?broadcasts with a vector shuffle. 2869*0fca6ea1SDimitry Andric Value *Op = CI->getArgOperand(0); 2870*0fca6ea1SDimitry Andric ElementCount EC = cast<VectorType>(CI->getType())->getElementCount(); 2871*0fca6ea1SDimitry Andric Type *MaskTy = VectorType::get(Type::getInt32Ty(C), EC); 2872*0fca6ea1SDimitry Andric SmallVector<int, 8> M; 2873*0fca6ea1SDimitry Andric ShuffleVectorInst::getShuffleMask(Constant::getNullValue(MaskTy), M); 2874*0fca6ea1SDimitry Andric Rep = Builder.CreateShuffleVector(Op, M); 2875*0fca6ea1SDimitry Andric 2876*0fca6ea1SDimitry Andric if (CI->arg_size() == 3) 2877*0fca6ea1SDimitry Andric Rep = emitX86Select(Builder, CI->getArgOperand(2), Rep, 2878*0fca6ea1SDimitry Andric CI->getArgOperand(1)); 2879*0fca6ea1SDimitry Andric } else if (Name.starts_with("sse2.padds.") || 2880*0fca6ea1SDimitry Andric Name.starts_with("avx2.padds.") || 2881*0fca6ea1SDimitry Andric Name.starts_with("avx512.padds.") || 2882*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.padds.")) { 2883*0fca6ea1SDimitry Andric Rep = upgradeX86BinaryIntrinsics(Builder, *CI, Intrinsic::sadd_sat); 2884*0fca6ea1SDimitry Andric } else if (Name.starts_with("sse2.psubs.") || 2885*0fca6ea1SDimitry Andric Name.starts_with("avx2.psubs.") || 2886*0fca6ea1SDimitry Andric Name.starts_with("avx512.psubs.") || 2887*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.psubs.")) { 2888*0fca6ea1SDimitry Andric Rep = upgradeX86BinaryIntrinsics(Builder, *CI, Intrinsic::ssub_sat); 2889*0fca6ea1SDimitry Andric } else if (Name.starts_with("sse2.paddus.") || 2890*0fca6ea1SDimitry Andric Name.starts_with("avx2.paddus.") || 2891*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.paddus.")) { 2892*0fca6ea1SDimitry Andric Rep = upgradeX86BinaryIntrinsics(Builder, *CI, Intrinsic::uadd_sat); 2893*0fca6ea1SDimitry Andric } else if (Name.starts_with("sse2.psubus.") || 2894*0fca6ea1SDimitry Andric Name.starts_with("avx2.psubus.") || 2895*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.psubus.")) { 2896*0fca6ea1SDimitry Andric Rep = upgradeX86BinaryIntrinsics(Builder, *CI, Intrinsic::usub_sat); 2897*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.palignr.")) { 2898*0fca6ea1SDimitry Andric Rep = upgradeX86ALIGNIntrinsics(Builder, CI->getArgOperand(0), 2899*0fca6ea1SDimitry Andric CI->getArgOperand(1), CI->getArgOperand(2), 2900*0fca6ea1SDimitry Andric CI->getArgOperand(3), CI->getArgOperand(4), 2901*0fca6ea1SDimitry Andric false); 2902*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.valign.")) { 2903*0fca6ea1SDimitry Andric Rep = upgradeX86ALIGNIntrinsics( 2904*0fca6ea1SDimitry Andric Builder, CI->getArgOperand(0), CI->getArgOperand(1), 2905*0fca6ea1SDimitry Andric CI->getArgOperand(2), CI->getArgOperand(3), CI->getArgOperand(4), true); 2906*0fca6ea1SDimitry Andric } else if (Name == "sse2.psll.dq" || Name == "avx2.psll.dq") { 2907*0fca6ea1SDimitry Andric // 128/256-bit shift left specified in bits. 2908*0fca6ea1SDimitry Andric unsigned Shift = cast<ConstantInt>(CI->getArgOperand(1))->getZExtValue(); 2909*0fca6ea1SDimitry Andric Rep = upgradeX86PSLLDQIntrinsics(Builder, CI->getArgOperand(0), 2910*0fca6ea1SDimitry Andric Shift / 8); // Shift is in bits. 2911*0fca6ea1SDimitry Andric } else if (Name == "sse2.psrl.dq" || Name == "avx2.psrl.dq") { 2912*0fca6ea1SDimitry Andric // 128/256-bit shift right specified in bits. 2913*0fca6ea1SDimitry Andric unsigned Shift = cast<ConstantInt>(CI->getArgOperand(1))->getZExtValue(); 2914*0fca6ea1SDimitry Andric Rep = upgradeX86PSRLDQIntrinsics(Builder, CI->getArgOperand(0), 2915*0fca6ea1SDimitry Andric Shift / 8); // Shift is in bits. 2916*0fca6ea1SDimitry Andric } else if (Name == "sse2.psll.dq.bs" || Name == "avx2.psll.dq.bs" || 2917*0fca6ea1SDimitry Andric Name == "avx512.psll.dq.512") { 2918*0fca6ea1SDimitry Andric // 128/256/512-bit shift left specified in bytes. 2919*0fca6ea1SDimitry Andric unsigned Shift = cast<ConstantInt>(CI->getArgOperand(1))->getZExtValue(); 2920*0fca6ea1SDimitry Andric Rep = upgradeX86PSLLDQIntrinsics(Builder, CI->getArgOperand(0), Shift); 2921*0fca6ea1SDimitry Andric } else if (Name == "sse2.psrl.dq.bs" || Name == "avx2.psrl.dq.bs" || 2922*0fca6ea1SDimitry Andric Name == "avx512.psrl.dq.512") { 2923*0fca6ea1SDimitry Andric // 128/256/512-bit shift right specified in bytes. 2924*0fca6ea1SDimitry Andric unsigned Shift = cast<ConstantInt>(CI->getArgOperand(1))->getZExtValue(); 2925*0fca6ea1SDimitry Andric Rep = upgradeX86PSRLDQIntrinsics(Builder, CI->getArgOperand(0), Shift); 2926*0fca6ea1SDimitry Andric } else if (Name == "sse41.pblendw" || Name.starts_with("sse41.blendp") || 2927*0fca6ea1SDimitry Andric Name.starts_with("avx.blend.p") || Name == "avx2.pblendw" || 2928*0fca6ea1SDimitry Andric Name.starts_with("avx2.pblendd.")) { 2929*0fca6ea1SDimitry Andric Value *Op0 = CI->getArgOperand(0); 2930*0fca6ea1SDimitry Andric Value *Op1 = CI->getArgOperand(1); 2931*0fca6ea1SDimitry Andric unsigned Imm = cast<ConstantInt>(CI->getArgOperand(2))->getZExtValue(); 2932*0fca6ea1SDimitry Andric auto *VecTy = cast<FixedVectorType>(CI->getType()); 2933*0fca6ea1SDimitry Andric unsigned NumElts = VecTy->getNumElements(); 2934*0fca6ea1SDimitry Andric 2935*0fca6ea1SDimitry Andric SmallVector<int, 16> Idxs(NumElts); 2936*0fca6ea1SDimitry Andric for (unsigned i = 0; i != NumElts; ++i) 2937*0fca6ea1SDimitry Andric Idxs[i] = ((Imm >> (i % 8)) & 1) ? i + NumElts : i; 2938*0fca6ea1SDimitry Andric 2939*0fca6ea1SDimitry Andric Rep = Builder.CreateShuffleVector(Op0, Op1, Idxs); 2940*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx.vinsertf128.") || 2941*0fca6ea1SDimitry Andric Name == "avx2.vinserti128" || 2942*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.insert")) { 2943*0fca6ea1SDimitry Andric Value *Op0 = CI->getArgOperand(0); 2944*0fca6ea1SDimitry Andric Value *Op1 = CI->getArgOperand(1); 2945*0fca6ea1SDimitry Andric unsigned Imm = cast<ConstantInt>(CI->getArgOperand(2))->getZExtValue(); 2946*0fca6ea1SDimitry Andric unsigned DstNumElts = 2947*0fca6ea1SDimitry Andric cast<FixedVectorType>(CI->getType())->getNumElements(); 2948*0fca6ea1SDimitry Andric unsigned SrcNumElts = 2949*0fca6ea1SDimitry Andric cast<FixedVectorType>(Op1->getType())->getNumElements(); 2950*0fca6ea1SDimitry Andric unsigned Scale = DstNumElts / SrcNumElts; 2951*0fca6ea1SDimitry Andric 2952*0fca6ea1SDimitry Andric // Mask off the high bits of the immediate value; hardware ignores those. 2953*0fca6ea1SDimitry Andric Imm = Imm % Scale; 2954*0fca6ea1SDimitry Andric 2955*0fca6ea1SDimitry Andric // Extend the second operand into a vector the size of the destination. 2956*0fca6ea1SDimitry Andric SmallVector<int, 8> Idxs(DstNumElts); 2957*0fca6ea1SDimitry Andric for (unsigned i = 0; i != SrcNumElts; ++i) 2958*0fca6ea1SDimitry Andric Idxs[i] = i; 2959*0fca6ea1SDimitry Andric for (unsigned i = SrcNumElts; i != DstNumElts; ++i) 2960*0fca6ea1SDimitry Andric Idxs[i] = SrcNumElts; 2961*0fca6ea1SDimitry Andric Rep = Builder.CreateShuffleVector(Op1, Idxs); 2962*0fca6ea1SDimitry Andric 2963*0fca6ea1SDimitry Andric // Insert the second operand into the first operand. 2964*0fca6ea1SDimitry Andric 2965*0fca6ea1SDimitry Andric // Note that there is no guarantee that instruction lowering will actually 2966*0fca6ea1SDimitry Andric // produce a vinsertf128 instruction for the created shuffles. In 2967*0fca6ea1SDimitry Andric // particular, the 0 immediate case involves no lane changes, so it can 2968*0fca6ea1SDimitry Andric // be handled as a blend. 2969*0fca6ea1SDimitry Andric 2970*0fca6ea1SDimitry Andric // Example of shuffle mask for 32-bit elements: 2971*0fca6ea1SDimitry Andric // Imm = 1 <i32 0, i32 1, i32 2, i32 3, i32 8, i32 9, i32 10, i32 11> 2972*0fca6ea1SDimitry Andric // Imm = 0 <i32 8, i32 9, i32 10, i32 11, i32 4, i32 5, i32 6, i32 7 > 2973*0fca6ea1SDimitry Andric 2974*0fca6ea1SDimitry Andric // First fill with identify mask. 2975*0fca6ea1SDimitry Andric for (unsigned i = 0; i != DstNumElts; ++i) 2976*0fca6ea1SDimitry Andric Idxs[i] = i; 2977*0fca6ea1SDimitry Andric // Then replace the elements where we need to insert. 2978*0fca6ea1SDimitry Andric for (unsigned i = 0; i != SrcNumElts; ++i) 2979*0fca6ea1SDimitry Andric Idxs[i + Imm * SrcNumElts] = i + DstNumElts; 2980*0fca6ea1SDimitry Andric Rep = Builder.CreateShuffleVector(Op0, Rep, Idxs); 2981*0fca6ea1SDimitry Andric 2982*0fca6ea1SDimitry Andric // If the intrinsic has a mask operand, handle that. 2983*0fca6ea1SDimitry Andric if (CI->arg_size() == 5) 2984*0fca6ea1SDimitry Andric Rep = emitX86Select(Builder, CI->getArgOperand(4), Rep, 2985*0fca6ea1SDimitry Andric CI->getArgOperand(3)); 2986*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx.vextractf128.") || 2987*0fca6ea1SDimitry Andric Name == "avx2.vextracti128" || 2988*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.vextract")) { 2989*0fca6ea1SDimitry Andric Value *Op0 = CI->getArgOperand(0); 2990*0fca6ea1SDimitry Andric unsigned Imm = cast<ConstantInt>(CI->getArgOperand(1))->getZExtValue(); 2991*0fca6ea1SDimitry Andric unsigned DstNumElts = 2992*0fca6ea1SDimitry Andric cast<FixedVectorType>(CI->getType())->getNumElements(); 2993*0fca6ea1SDimitry Andric unsigned SrcNumElts = 2994*0fca6ea1SDimitry Andric cast<FixedVectorType>(Op0->getType())->getNumElements(); 2995*0fca6ea1SDimitry Andric unsigned Scale = SrcNumElts / DstNumElts; 2996*0fca6ea1SDimitry Andric 2997*0fca6ea1SDimitry Andric // Mask off the high bits of the immediate value; hardware ignores those. 2998*0fca6ea1SDimitry Andric Imm = Imm % Scale; 2999*0fca6ea1SDimitry Andric 3000*0fca6ea1SDimitry Andric // Get indexes for the subvector of the input vector. 3001*0fca6ea1SDimitry Andric SmallVector<int, 8> Idxs(DstNumElts); 3002*0fca6ea1SDimitry Andric for (unsigned i = 0; i != DstNumElts; ++i) { 3003*0fca6ea1SDimitry Andric Idxs[i] = i + (Imm * DstNumElts); 3004*0fca6ea1SDimitry Andric } 3005*0fca6ea1SDimitry Andric Rep = Builder.CreateShuffleVector(Op0, Op0, Idxs); 3006*0fca6ea1SDimitry Andric 3007*0fca6ea1SDimitry Andric // If the intrinsic has a mask operand, handle that. 3008*0fca6ea1SDimitry Andric if (CI->arg_size() == 4) 3009*0fca6ea1SDimitry Andric Rep = emitX86Select(Builder, CI->getArgOperand(3), Rep, 3010*0fca6ea1SDimitry Andric CI->getArgOperand(2)); 3011*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.perm.df.") || 3012*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.perm.di.")) { 3013*0fca6ea1SDimitry Andric Value *Op0 = CI->getArgOperand(0); 3014*0fca6ea1SDimitry Andric unsigned Imm = cast<ConstantInt>(CI->getArgOperand(1))->getZExtValue(); 3015*0fca6ea1SDimitry Andric auto *VecTy = cast<FixedVectorType>(CI->getType()); 3016*0fca6ea1SDimitry Andric unsigned NumElts = VecTy->getNumElements(); 3017*0fca6ea1SDimitry Andric 3018*0fca6ea1SDimitry Andric SmallVector<int, 8> Idxs(NumElts); 3019*0fca6ea1SDimitry Andric for (unsigned i = 0; i != NumElts; ++i) 3020*0fca6ea1SDimitry Andric Idxs[i] = (i & ~0x3) + ((Imm >> (2 * (i & 0x3))) & 3); 3021*0fca6ea1SDimitry Andric 3022*0fca6ea1SDimitry Andric Rep = Builder.CreateShuffleVector(Op0, Op0, Idxs); 3023*0fca6ea1SDimitry Andric 3024*0fca6ea1SDimitry Andric if (CI->arg_size() == 4) 3025*0fca6ea1SDimitry Andric Rep = emitX86Select(Builder, CI->getArgOperand(3), Rep, 3026*0fca6ea1SDimitry Andric CI->getArgOperand(2)); 3027*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx.vperm2f128.") || Name == "avx2.vperm2i128") { 3028*0fca6ea1SDimitry Andric // The immediate permute control byte looks like this: 3029*0fca6ea1SDimitry Andric // [1:0] - select 128 bits from sources for low half of destination 3030*0fca6ea1SDimitry Andric // [2] - ignore 3031*0fca6ea1SDimitry Andric // [3] - zero low half of destination 3032*0fca6ea1SDimitry Andric // [5:4] - select 128 bits from sources for high half of destination 3033*0fca6ea1SDimitry Andric // [6] - ignore 3034*0fca6ea1SDimitry Andric // [7] - zero high half of destination 3035*0fca6ea1SDimitry Andric 3036*0fca6ea1SDimitry Andric uint8_t Imm = cast<ConstantInt>(CI->getArgOperand(2))->getZExtValue(); 3037*0fca6ea1SDimitry Andric 3038*0fca6ea1SDimitry Andric unsigned NumElts = cast<FixedVectorType>(CI->getType())->getNumElements(); 3039*0fca6ea1SDimitry Andric unsigned HalfSize = NumElts / 2; 3040*0fca6ea1SDimitry Andric SmallVector<int, 8> ShuffleMask(NumElts); 3041*0fca6ea1SDimitry Andric 3042*0fca6ea1SDimitry Andric // Determine which operand(s) are actually in use for this instruction. 3043*0fca6ea1SDimitry Andric Value *V0 = (Imm & 0x02) ? CI->getArgOperand(1) : CI->getArgOperand(0); 3044*0fca6ea1SDimitry Andric Value *V1 = (Imm & 0x20) ? CI->getArgOperand(1) : CI->getArgOperand(0); 3045*0fca6ea1SDimitry Andric 3046*0fca6ea1SDimitry Andric // If needed, replace operands based on zero mask. 3047*0fca6ea1SDimitry Andric V0 = (Imm & 0x08) ? ConstantAggregateZero::get(CI->getType()) : V0; 3048*0fca6ea1SDimitry Andric V1 = (Imm & 0x80) ? ConstantAggregateZero::get(CI->getType()) : V1; 3049*0fca6ea1SDimitry Andric 3050*0fca6ea1SDimitry Andric // Permute low half of result. 3051*0fca6ea1SDimitry Andric unsigned StartIndex = (Imm & 0x01) ? HalfSize : 0; 3052*0fca6ea1SDimitry Andric for (unsigned i = 0; i < HalfSize; ++i) 3053*0fca6ea1SDimitry Andric ShuffleMask[i] = StartIndex + i; 3054*0fca6ea1SDimitry Andric 3055*0fca6ea1SDimitry Andric // Permute high half of result. 3056*0fca6ea1SDimitry Andric StartIndex = (Imm & 0x10) ? HalfSize : 0; 3057*0fca6ea1SDimitry Andric for (unsigned i = 0; i < HalfSize; ++i) 3058*0fca6ea1SDimitry Andric ShuffleMask[i + HalfSize] = NumElts + StartIndex + i; 3059*0fca6ea1SDimitry Andric 3060*0fca6ea1SDimitry Andric Rep = Builder.CreateShuffleVector(V0, V1, ShuffleMask); 3061*0fca6ea1SDimitry Andric 3062*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx.vpermil.") || Name == "sse2.pshuf.d" || 3063*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.vpermil.p") || 3064*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.pshuf.d.")) { 3065*0fca6ea1SDimitry Andric Value *Op0 = CI->getArgOperand(0); 3066*0fca6ea1SDimitry Andric unsigned Imm = cast<ConstantInt>(CI->getArgOperand(1))->getZExtValue(); 3067*0fca6ea1SDimitry Andric auto *VecTy = cast<FixedVectorType>(CI->getType()); 3068*0fca6ea1SDimitry Andric unsigned NumElts = VecTy->getNumElements(); 3069*0fca6ea1SDimitry Andric // Calculate the size of each index in the immediate. 3070*0fca6ea1SDimitry Andric unsigned IdxSize = 64 / VecTy->getScalarSizeInBits(); 3071*0fca6ea1SDimitry Andric unsigned IdxMask = ((1 << IdxSize) - 1); 3072*0fca6ea1SDimitry Andric 3073*0fca6ea1SDimitry Andric SmallVector<int, 8> Idxs(NumElts); 3074*0fca6ea1SDimitry Andric // Lookup the bits for this element, wrapping around the immediate every 3075*0fca6ea1SDimitry Andric // 8-bits. Elements are grouped into sets of 2 or 4 elements so we need 3076*0fca6ea1SDimitry Andric // to offset by the first index of each group. 3077*0fca6ea1SDimitry Andric for (unsigned i = 0; i != NumElts; ++i) 3078*0fca6ea1SDimitry Andric Idxs[i] = ((Imm >> ((i * IdxSize) % 8)) & IdxMask) | (i & ~IdxMask); 3079*0fca6ea1SDimitry Andric 3080*0fca6ea1SDimitry Andric Rep = Builder.CreateShuffleVector(Op0, Op0, Idxs); 3081*0fca6ea1SDimitry Andric 3082*0fca6ea1SDimitry Andric if (CI->arg_size() == 4) 3083*0fca6ea1SDimitry Andric Rep = emitX86Select(Builder, CI->getArgOperand(3), Rep, 3084*0fca6ea1SDimitry Andric CI->getArgOperand(2)); 3085*0fca6ea1SDimitry Andric } else if (Name == "sse2.pshufl.w" || 3086*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.pshufl.w.")) { 3087*0fca6ea1SDimitry Andric Value *Op0 = CI->getArgOperand(0); 3088*0fca6ea1SDimitry Andric unsigned Imm = cast<ConstantInt>(CI->getArgOperand(1))->getZExtValue(); 3089*0fca6ea1SDimitry Andric unsigned NumElts = cast<FixedVectorType>(CI->getType())->getNumElements(); 3090*0fca6ea1SDimitry Andric 3091*0fca6ea1SDimitry Andric SmallVector<int, 16> Idxs(NumElts); 3092*0fca6ea1SDimitry Andric for (unsigned l = 0; l != NumElts; l += 8) { 3093*0fca6ea1SDimitry Andric for (unsigned i = 0; i != 4; ++i) 3094*0fca6ea1SDimitry Andric Idxs[i + l] = ((Imm >> (2 * i)) & 0x3) + l; 3095*0fca6ea1SDimitry Andric for (unsigned i = 4; i != 8; ++i) 3096*0fca6ea1SDimitry Andric Idxs[i + l] = i + l; 3097*0fca6ea1SDimitry Andric } 3098*0fca6ea1SDimitry Andric 3099*0fca6ea1SDimitry Andric Rep = Builder.CreateShuffleVector(Op0, Op0, Idxs); 3100*0fca6ea1SDimitry Andric 3101*0fca6ea1SDimitry Andric if (CI->arg_size() == 4) 3102*0fca6ea1SDimitry Andric Rep = emitX86Select(Builder, CI->getArgOperand(3), Rep, 3103*0fca6ea1SDimitry Andric CI->getArgOperand(2)); 3104*0fca6ea1SDimitry Andric } else if (Name == "sse2.pshufh.w" || 3105*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.pshufh.w.")) { 3106*0fca6ea1SDimitry Andric Value *Op0 = CI->getArgOperand(0); 3107*0fca6ea1SDimitry Andric unsigned Imm = cast<ConstantInt>(CI->getArgOperand(1))->getZExtValue(); 3108*0fca6ea1SDimitry Andric unsigned NumElts = cast<FixedVectorType>(CI->getType())->getNumElements(); 3109*0fca6ea1SDimitry Andric 3110*0fca6ea1SDimitry Andric SmallVector<int, 16> Idxs(NumElts); 3111*0fca6ea1SDimitry Andric for (unsigned l = 0; l != NumElts; l += 8) { 3112*0fca6ea1SDimitry Andric for (unsigned i = 0; i != 4; ++i) 3113*0fca6ea1SDimitry Andric Idxs[i + l] = i + l; 3114*0fca6ea1SDimitry Andric for (unsigned i = 0; i != 4; ++i) 3115*0fca6ea1SDimitry Andric Idxs[i + l + 4] = ((Imm >> (2 * i)) & 0x3) + 4 + l; 3116*0fca6ea1SDimitry Andric } 3117*0fca6ea1SDimitry Andric 3118*0fca6ea1SDimitry Andric Rep = Builder.CreateShuffleVector(Op0, Op0, Idxs); 3119*0fca6ea1SDimitry Andric 3120*0fca6ea1SDimitry Andric if (CI->arg_size() == 4) 3121*0fca6ea1SDimitry Andric Rep = emitX86Select(Builder, CI->getArgOperand(3), Rep, 3122*0fca6ea1SDimitry Andric CI->getArgOperand(2)); 3123*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.shuf.p")) { 3124*0fca6ea1SDimitry Andric Value *Op0 = CI->getArgOperand(0); 3125*0fca6ea1SDimitry Andric Value *Op1 = CI->getArgOperand(1); 3126*0fca6ea1SDimitry Andric unsigned Imm = cast<ConstantInt>(CI->getArgOperand(2))->getZExtValue(); 3127*0fca6ea1SDimitry Andric unsigned NumElts = cast<FixedVectorType>(CI->getType())->getNumElements(); 3128*0fca6ea1SDimitry Andric 3129*0fca6ea1SDimitry Andric unsigned NumLaneElts = 128 / CI->getType()->getScalarSizeInBits(); 3130*0fca6ea1SDimitry Andric unsigned HalfLaneElts = NumLaneElts / 2; 3131*0fca6ea1SDimitry Andric 3132*0fca6ea1SDimitry Andric SmallVector<int, 16> Idxs(NumElts); 3133*0fca6ea1SDimitry Andric for (unsigned i = 0; i != NumElts; ++i) { 3134*0fca6ea1SDimitry Andric // Base index is the starting element of the lane. 3135*0fca6ea1SDimitry Andric Idxs[i] = i - (i % NumLaneElts); 3136*0fca6ea1SDimitry Andric // If we are half way through the lane switch to the other source. 3137*0fca6ea1SDimitry Andric if ((i % NumLaneElts) >= HalfLaneElts) 3138*0fca6ea1SDimitry Andric Idxs[i] += NumElts; 3139*0fca6ea1SDimitry Andric // Now select the specific element. By adding HalfLaneElts bits from 3140*0fca6ea1SDimitry Andric // the immediate. Wrapping around the immediate every 8-bits. 3141*0fca6ea1SDimitry Andric Idxs[i] += (Imm >> ((i * HalfLaneElts) % 8)) & ((1 << HalfLaneElts) - 1); 3142*0fca6ea1SDimitry Andric } 3143*0fca6ea1SDimitry Andric 3144*0fca6ea1SDimitry Andric Rep = Builder.CreateShuffleVector(Op0, Op1, Idxs); 3145*0fca6ea1SDimitry Andric 3146*0fca6ea1SDimitry Andric Rep = 3147*0fca6ea1SDimitry Andric emitX86Select(Builder, CI->getArgOperand(4), Rep, CI->getArgOperand(3)); 3148*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.movddup") || 3149*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.movshdup") || 3150*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.movsldup")) { 3151*0fca6ea1SDimitry Andric Value *Op0 = CI->getArgOperand(0); 3152*0fca6ea1SDimitry Andric unsigned NumElts = cast<FixedVectorType>(CI->getType())->getNumElements(); 3153*0fca6ea1SDimitry Andric unsigned NumLaneElts = 128 / CI->getType()->getScalarSizeInBits(); 3154*0fca6ea1SDimitry Andric 3155*0fca6ea1SDimitry Andric unsigned Offset = 0; 3156*0fca6ea1SDimitry Andric if (Name.starts_with("avx512.mask.movshdup.")) 3157*0fca6ea1SDimitry Andric Offset = 1; 3158*0fca6ea1SDimitry Andric 3159*0fca6ea1SDimitry Andric SmallVector<int, 16> Idxs(NumElts); 3160*0fca6ea1SDimitry Andric for (unsigned l = 0; l != NumElts; l += NumLaneElts) 3161*0fca6ea1SDimitry Andric for (unsigned i = 0; i != NumLaneElts; i += 2) { 3162*0fca6ea1SDimitry Andric Idxs[i + l + 0] = i + l + Offset; 3163*0fca6ea1SDimitry Andric Idxs[i + l + 1] = i + l + Offset; 3164*0fca6ea1SDimitry Andric } 3165*0fca6ea1SDimitry Andric 3166*0fca6ea1SDimitry Andric Rep = Builder.CreateShuffleVector(Op0, Op0, Idxs); 3167*0fca6ea1SDimitry Andric 3168*0fca6ea1SDimitry Andric Rep = 3169*0fca6ea1SDimitry Andric emitX86Select(Builder, CI->getArgOperand(2), Rep, CI->getArgOperand(1)); 3170*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.punpckl") || 3171*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.unpckl.")) { 3172*0fca6ea1SDimitry Andric Value *Op0 = CI->getArgOperand(0); 3173*0fca6ea1SDimitry Andric Value *Op1 = CI->getArgOperand(1); 3174*0fca6ea1SDimitry Andric int NumElts = cast<FixedVectorType>(CI->getType())->getNumElements(); 3175*0fca6ea1SDimitry Andric int NumLaneElts = 128 / CI->getType()->getScalarSizeInBits(); 3176*0fca6ea1SDimitry Andric 3177*0fca6ea1SDimitry Andric SmallVector<int, 64> Idxs(NumElts); 3178*0fca6ea1SDimitry Andric for (int l = 0; l != NumElts; l += NumLaneElts) 3179*0fca6ea1SDimitry Andric for (int i = 0; i != NumLaneElts; ++i) 3180*0fca6ea1SDimitry Andric Idxs[i + l] = l + (i / 2) + NumElts * (i % 2); 3181*0fca6ea1SDimitry Andric 3182*0fca6ea1SDimitry Andric Rep = Builder.CreateShuffleVector(Op0, Op1, Idxs); 3183*0fca6ea1SDimitry Andric 3184*0fca6ea1SDimitry Andric Rep = 3185*0fca6ea1SDimitry Andric emitX86Select(Builder, CI->getArgOperand(3), Rep, CI->getArgOperand(2)); 3186*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.punpckh") || 3187*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.unpckh.")) { 3188*0fca6ea1SDimitry Andric Value *Op0 = CI->getArgOperand(0); 3189*0fca6ea1SDimitry Andric Value *Op1 = CI->getArgOperand(1); 3190*0fca6ea1SDimitry Andric int NumElts = cast<FixedVectorType>(CI->getType())->getNumElements(); 3191*0fca6ea1SDimitry Andric int NumLaneElts = 128 / CI->getType()->getScalarSizeInBits(); 3192*0fca6ea1SDimitry Andric 3193*0fca6ea1SDimitry Andric SmallVector<int, 64> Idxs(NumElts); 3194*0fca6ea1SDimitry Andric for (int l = 0; l != NumElts; l += NumLaneElts) 3195*0fca6ea1SDimitry Andric for (int i = 0; i != NumLaneElts; ++i) 3196*0fca6ea1SDimitry Andric Idxs[i + l] = (NumLaneElts / 2) + l + (i / 2) + NumElts * (i % 2); 3197*0fca6ea1SDimitry Andric 3198*0fca6ea1SDimitry Andric Rep = Builder.CreateShuffleVector(Op0, Op1, Idxs); 3199*0fca6ea1SDimitry Andric 3200*0fca6ea1SDimitry Andric Rep = 3201*0fca6ea1SDimitry Andric emitX86Select(Builder, CI->getArgOperand(3), Rep, CI->getArgOperand(2)); 3202*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.and.") || 3203*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.pand.")) { 3204*0fca6ea1SDimitry Andric VectorType *FTy = cast<VectorType>(CI->getType()); 3205*0fca6ea1SDimitry Andric VectorType *ITy = VectorType::getInteger(FTy); 3206*0fca6ea1SDimitry Andric Rep = Builder.CreateAnd(Builder.CreateBitCast(CI->getArgOperand(0), ITy), 3207*0fca6ea1SDimitry Andric Builder.CreateBitCast(CI->getArgOperand(1), ITy)); 3208*0fca6ea1SDimitry Andric Rep = Builder.CreateBitCast(Rep, FTy); 3209*0fca6ea1SDimitry Andric Rep = 3210*0fca6ea1SDimitry Andric emitX86Select(Builder, CI->getArgOperand(3), Rep, CI->getArgOperand(2)); 3211*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.andn.") || 3212*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.pandn.")) { 3213*0fca6ea1SDimitry Andric VectorType *FTy = cast<VectorType>(CI->getType()); 3214*0fca6ea1SDimitry Andric VectorType *ITy = VectorType::getInteger(FTy); 3215*0fca6ea1SDimitry Andric Rep = Builder.CreateNot(Builder.CreateBitCast(CI->getArgOperand(0), ITy)); 3216*0fca6ea1SDimitry Andric Rep = Builder.CreateAnd(Rep, 3217*0fca6ea1SDimitry Andric Builder.CreateBitCast(CI->getArgOperand(1), ITy)); 3218*0fca6ea1SDimitry Andric Rep = Builder.CreateBitCast(Rep, FTy); 3219*0fca6ea1SDimitry Andric Rep = 3220*0fca6ea1SDimitry Andric emitX86Select(Builder, CI->getArgOperand(3), Rep, CI->getArgOperand(2)); 3221*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.or.") || 3222*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.por.")) { 3223*0fca6ea1SDimitry Andric VectorType *FTy = cast<VectorType>(CI->getType()); 3224*0fca6ea1SDimitry Andric VectorType *ITy = VectorType::getInteger(FTy); 3225*0fca6ea1SDimitry Andric Rep = Builder.CreateOr(Builder.CreateBitCast(CI->getArgOperand(0), ITy), 3226*0fca6ea1SDimitry Andric Builder.CreateBitCast(CI->getArgOperand(1), ITy)); 3227*0fca6ea1SDimitry Andric Rep = Builder.CreateBitCast(Rep, FTy); 3228*0fca6ea1SDimitry Andric Rep = 3229*0fca6ea1SDimitry Andric emitX86Select(Builder, CI->getArgOperand(3), Rep, CI->getArgOperand(2)); 3230*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.xor.") || 3231*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.pxor.")) { 3232*0fca6ea1SDimitry Andric VectorType *FTy = cast<VectorType>(CI->getType()); 3233*0fca6ea1SDimitry Andric VectorType *ITy = VectorType::getInteger(FTy); 3234*0fca6ea1SDimitry Andric Rep = Builder.CreateXor(Builder.CreateBitCast(CI->getArgOperand(0), ITy), 3235*0fca6ea1SDimitry Andric Builder.CreateBitCast(CI->getArgOperand(1), ITy)); 3236*0fca6ea1SDimitry Andric Rep = Builder.CreateBitCast(Rep, FTy); 3237*0fca6ea1SDimitry Andric Rep = 3238*0fca6ea1SDimitry Andric emitX86Select(Builder, CI->getArgOperand(3), Rep, CI->getArgOperand(2)); 3239*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.padd.")) { 3240*0fca6ea1SDimitry Andric Rep = Builder.CreateAdd(CI->getArgOperand(0), CI->getArgOperand(1)); 3241*0fca6ea1SDimitry Andric Rep = 3242*0fca6ea1SDimitry Andric emitX86Select(Builder, CI->getArgOperand(3), Rep, CI->getArgOperand(2)); 3243*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.psub.")) { 3244*0fca6ea1SDimitry Andric Rep = Builder.CreateSub(CI->getArgOperand(0), CI->getArgOperand(1)); 3245*0fca6ea1SDimitry Andric Rep = 3246*0fca6ea1SDimitry Andric emitX86Select(Builder, CI->getArgOperand(3), Rep, CI->getArgOperand(2)); 3247*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.pmull.")) { 3248*0fca6ea1SDimitry Andric Rep = Builder.CreateMul(CI->getArgOperand(0), CI->getArgOperand(1)); 3249*0fca6ea1SDimitry Andric Rep = 3250*0fca6ea1SDimitry Andric emitX86Select(Builder, CI->getArgOperand(3), Rep, CI->getArgOperand(2)); 3251*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.add.p")) { 3252*0fca6ea1SDimitry Andric if (Name.ends_with(".512")) { 3253*0fca6ea1SDimitry Andric Intrinsic::ID IID; 3254*0fca6ea1SDimitry Andric if (Name[17] == 's') 3255*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_add_ps_512; 3256*0fca6ea1SDimitry Andric else 3257*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_add_pd_512; 3258*0fca6ea1SDimitry Andric 3259*0fca6ea1SDimitry Andric Rep = Builder.CreateCall( 3260*0fca6ea1SDimitry Andric Intrinsic::getDeclaration(F->getParent(), IID), 3261*0fca6ea1SDimitry Andric {CI->getArgOperand(0), CI->getArgOperand(1), CI->getArgOperand(4)}); 3262*0fca6ea1SDimitry Andric } else { 3263*0fca6ea1SDimitry Andric Rep = Builder.CreateFAdd(CI->getArgOperand(0), CI->getArgOperand(1)); 3264*0fca6ea1SDimitry Andric } 3265*0fca6ea1SDimitry Andric Rep = 3266*0fca6ea1SDimitry Andric emitX86Select(Builder, CI->getArgOperand(3), Rep, CI->getArgOperand(2)); 3267*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.div.p")) { 3268*0fca6ea1SDimitry Andric if (Name.ends_with(".512")) { 3269*0fca6ea1SDimitry Andric Intrinsic::ID IID; 3270*0fca6ea1SDimitry Andric if (Name[17] == 's') 3271*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_div_ps_512; 3272*0fca6ea1SDimitry Andric else 3273*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_div_pd_512; 3274*0fca6ea1SDimitry Andric 3275*0fca6ea1SDimitry Andric Rep = Builder.CreateCall( 3276*0fca6ea1SDimitry Andric Intrinsic::getDeclaration(F->getParent(), IID), 3277*0fca6ea1SDimitry Andric {CI->getArgOperand(0), CI->getArgOperand(1), CI->getArgOperand(4)}); 3278*0fca6ea1SDimitry Andric } else { 3279*0fca6ea1SDimitry Andric Rep = Builder.CreateFDiv(CI->getArgOperand(0), CI->getArgOperand(1)); 3280*0fca6ea1SDimitry Andric } 3281*0fca6ea1SDimitry Andric Rep = 3282*0fca6ea1SDimitry Andric emitX86Select(Builder, CI->getArgOperand(3), Rep, CI->getArgOperand(2)); 3283*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.mul.p")) { 3284*0fca6ea1SDimitry Andric if (Name.ends_with(".512")) { 3285*0fca6ea1SDimitry Andric Intrinsic::ID IID; 3286*0fca6ea1SDimitry Andric if (Name[17] == 's') 3287*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_mul_ps_512; 3288*0fca6ea1SDimitry Andric else 3289*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_mul_pd_512; 3290*0fca6ea1SDimitry Andric 3291*0fca6ea1SDimitry Andric Rep = Builder.CreateCall( 3292*0fca6ea1SDimitry Andric Intrinsic::getDeclaration(F->getParent(), IID), 3293*0fca6ea1SDimitry Andric {CI->getArgOperand(0), CI->getArgOperand(1), CI->getArgOperand(4)}); 3294*0fca6ea1SDimitry Andric } else { 3295*0fca6ea1SDimitry Andric Rep = Builder.CreateFMul(CI->getArgOperand(0), CI->getArgOperand(1)); 3296*0fca6ea1SDimitry Andric } 3297*0fca6ea1SDimitry Andric Rep = 3298*0fca6ea1SDimitry Andric emitX86Select(Builder, CI->getArgOperand(3), Rep, CI->getArgOperand(2)); 3299*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.sub.p")) { 3300*0fca6ea1SDimitry Andric if (Name.ends_with(".512")) { 3301*0fca6ea1SDimitry Andric Intrinsic::ID IID; 3302*0fca6ea1SDimitry Andric if (Name[17] == 's') 3303*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_sub_ps_512; 3304*0fca6ea1SDimitry Andric else 3305*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_sub_pd_512; 3306*0fca6ea1SDimitry Andric 3307*0fca6ea1SDimitry Andric Rep = Builder.CreateCall( 3308*0fca6ea1SDimitry Andric Intrinsic::getDeclaration(F->getParent(), IID), 3309*0fca6ea1SDimitry Andric {CI->getArgOperand(0), CI->getArgOperand(1), CI->getArgOperand(4)}); 3310*0fca6ea1SDimitry Andric } else { 3311*0fca6ea1SDimitry Andric Rep = Builder.CreateFSub(CI->getArgOperand(0), CI->getArgOperand(1)); 3312*0fca6ea1SDimitry Andric } 3313*0fca6ea1SDimitry Andric Rep = 3314*0fca6ea1SDimitry Andric emitX86Select(Builder, CI->getArgOperand(3), Rep, CI->getArgOperand(2)); 3315*0fca6ea1SDimitry Andric } else if ((Name.starts_with("avx512.mask.max.p") || 3316*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.min.p")) && 3317*0fca6ea1SDimitry Andric Name.drop_front(18) == ".512") { 3318*0fca6ea1SDimitry Andric bool IsDouble = Name[17] == 'd'; 3319*0fca6ea1SDimitry Andric bool IsMin = Name[13] == 'i'; 3320*0fca6ea1SDimitry Andric static const Intrinsic::ID MinMaxTbl[2][2] = { 3321*0fca6ea1SDimitry Andric {Intrinsic::x86_avx512_max_ps_512, Intrinsic::x86_avx512_max_pd_512}, 3322*0fca6ea1SDimitry Andric {Intrinsic::x86_avx512_min_ps_512, Intrinsic::x86_avx512_min_pd_512}}; 3323*0fca6ea1SDimitry Andric Intrinsic::ID IID = MinMaxTbl[IsMin][IsDouble]; 3324*0fca6ea1SDimitry Andric 3325*0fca6ea1SDimitry Andric Rep = Builder.CreateCall( 3326*0fca6ea1SDimitry Andric Intrinsic::getDeclaration(F->getParent(), IID), 3327*0fca6ea1SDimitry Andric {CI->getArgOperand(0), CI->getArgOperand(1), CI->getArgOperand(4)}); 3328*0fca6ea1SDimitry Andric Rep = 3329*0fca6ea1SDimitry Andric emitX86Select(Builder, CI->getArgOperand(3), Rep, CI->getArgOperand(2)); 3330*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.lzcnt.")) { 3331*0fca6ea1SDimitry Andric Rep = 3332*0fca6ea1SDimitry Andric Builder.CreateCall(Intrinsic::getDeclaration( 3333*0fca6ea1SDimitry Andric F->getParent(), Intrinsic::ctlz, CI->getType()), 3334*0fca6ea1SDimitry Andric {CI->getArgOperand(0), Builder.getInt1(false)}); 3335*0fca6ea1SDimitry Andric Rep = 3336*0fca6ea1SDimitry Andric emitX86Select(Builder, CI->getArgOperand(2), Rep, CI->getArgOperand(1)); 3337*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.psll")) { 3338*0fca6ea1SDimitry Andric bool IsImmediate = Name[16] == 'i' || (Name.size() > 18 && Name[18] == 'i'); 3339*0fca6ea1SDimitry Andric bool IsVariable = Name[16] == 'v'; 3340*0fca6ea1SDimitry Andric char Size = Name[16] == '.' ? Name[17] 3341*0fca6ea1SDimitry Andric : Name[17] == '.' ? Name[18] 3342*0fca6ea1SDimitry Andric : Name[18] == '.' ? Name[19] 3343*0fca6ea1SDimitry Andric : Name[20]; 3344*0fca6ea1SDimitry Andric 3345*0fca6ea1SDimitry Andric Intrinsic::ID IID; 3346*0fca6ea1SDimitry Andric if (IsVariable && Name[17] != '.') { 3347*0fca6ea1SDimitry Andric if (Size == 'd' && Name[17] == '2') // avx512.mask.psllv2.di 3348*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx2_psllv_q; 3349*0fca6ea1SDimitry Andric else if (Size == 'd' && Name[17] == '4') // avx512.mask.psllv4.di 3350*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx2_psllv_q_256; 3351*0fca6ea1SDimitry Andric else if (Size == 's' && Name[17] == '4') // avx512.mask.psllv4.si 3352*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx2_psllv_d; 3353*0fca6ea1SDimitry Andric else if (Size == 's' && Name[17] == '8') // avx512.mask.psllv8.si 3354*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx2_psllv_d_256; 3355*0fca6ea1SDimitry Andric else if (Size == 'h' && Name[17] == '8') // avx512.mask.psllv8.hi 3356*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_psllv_w_128; 3357*0fca6ea1SDimitry Andric else if (Size == 'h' && Name[17] == '1') // avx512.mask.psllv16.hi 3358*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_psllv_w_256; 3359*0fca6ea1SDimitry Andric else if (Name[17] == '3' && Name[18] == '2') // avx512.mask.psllv32hi 3360*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_psllv_w_512; 3361*0fca6ea1SDimitry Andric else 3362*0fca6ea1SDimitry Andric llvm_unreachable("Unexpected size"); 3363*0fca6ea1SDimitry Andric } else if (Name.ends_with(".128")) { 3364*0fca6ea1SDimitry Andric if (Size == 'd') // avx512.mask.psll.d.128, avx512.mask.psll.di.128 3365*0fca6ea1SDimitry Andric IID = IsImmediate ? Intrinsic::x86_sse2_pslli_d 3366*0fca6ea1SDimitry Andric : Intrinsic::x86_sse2_psll_d; 3367*0fca6ea1SDimitry Andric else if (Size == 'q') // avx512.mask.psll.q.128, avx512.mask.psll.qi.128 3368*0fca6ea1SDimitry Andric IID = IsImmediate ? Intrinsic::x86_sse2_pslli_q 3369*0fca6ea1SDimitry Andric : Intrinsic::x86_sse2_psll_q; 3370*0fca6ea1SDimitry Andric else if (Size == 'w') // avx512.mask.psll.w.128, avx512.mask.psll.wi.128 3371*0fca6ea1SDimitry Andric IID = IsImmediate ? Intrinsic::x86_sse2_pslli_w 3372*0fca6ea1SDimitry Andric : Intrinsic::x86_sse2_psll_w; 3373*0fca6ea1SDimitry Andric else 3374*0fca6ea1SDimitry Andric llvm_unreachable("Unexpected size"); 3375*0fca6ea1SDimitry Andric } else if (Name.ends_with(".256")) { 3376*0fca6ea1SDimitry Andric if (Size == 'd') // avx512.mask.psll.d.256, avx512.mask.psll.di.256 3377*0fca6ea1SDimitry Andric IID = IsImmediate ? Intrinsic::x86_avx2_pslli_d 3378*0fca6ea1SDimitry Andric : Intrinsic::x86_avx2_psll_d; 3379*0fca6ea1SDimitry Andric else if (Size == 'q') // avx512.mask.psll.q.256, avx512.mask.psll.qi.256 3380*0fca6ea1SDimitry Andric IID = IsImmediate ? Intrinsic::x86_avx2_pslli_q 3381*0fca6ea1SDimitry Andric : Intrinsic::x86_avx2_psll_q; 3382*0fca6ea1SDimitry Andric else if (Size == 'w') // avx512.mask.psll.w.256, avx512.mask.psll.wi.256 3383*0fca6ea1SDimitry Andric IID = IsImmediate ? Intrinsic::x86_avx2_pslli_w 3384*0fca6ea1SDimitry Andric : Intrinsic::x86_avx2_psll_w; 3385*0fca6ea1SDimitry Andric else 3386*0fca6ea1SDimitry Andric llvm_unreachable("Unexpected size"); 3387*0fca6ea1SDimitry Andric } else { 3388*0fca6ea1SDimitry Andric if (Size == 'd') // psll.di.512, pslli.d, psll.d, psllv.d.512 3389*0fca6ea1SDimitry Andric IID = IsImmediate ? Intrinsic::x86_avx512_pslli_d_512 3390*0fca6ea1SDimitry Andric : IsVariable ? Intrinsic::x86_avx512_psllv_d_512 3391*0fca6ea1SDimitry Andric : Intrinsic::x86_avx512_psll_d_512; 3392*0fca6ea1SDimitry Andric else if (Size == 'q') // psll.qi.512, pslli.q, psll.q, psllv.q.512 3393*0fca6ea1SDimitry Andric IID = IsImmediate ? Intrinsic::x86_avx512_pslli_q_512 3394*0fca6ea1SDimitry Andric : IsVariable ? Intrinsic::x86_avx512_psllv_q_512 3395*0fca6ea1SDimitry Andric : Intrinsic::x86_avx512_psll_q_512; 3396*0fca6ea1SDimitry Andric else if (Size == 'w') // psll.wi.512, pslli.w, psll.w 3397*0fca6ea1SDimitry Andric IID = IsImmediate ? Intrinsic::x86_avx512_pslli_w_512 3398*0fca6ea1SDimitry Andric : Intrinsic::x86_avx512_psll_w_512; 3399*0fca6ea1SDimitry Andric else 3400*0fca6ea1SDimitry Andric llvm_unreachable("Unexpected size"); 3401*0fca6ea1SDimitry Andric } 3402*0fca6ea1SDimitry Andric 3403*0fca6ea1SDimitry Andric Rep = upgradeX86MaskedShift(Builder, *CI, IID); 3404*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.psrl")) { 3405*0fca6ea1SDimitry Andric bool IsImmediate = Name[16] == 'i' || (Name.size() > 18 && Name[18] == 'i'); 3406*0fca6ea1SDimitry Andric bool IsVariable = Name[16] == 'v'; 3407*0fca6ea1SDimitry Andric char Size = Name[16] == '.' ? Name[17] 3408*0fca6ea1SDimitry Andric : Name[17] == '.' ? Name[18] 3409*0fca6ea1SDimitry Andric : Name[18] == '.' ? Name[19] 3410*0fca6ea1SDimitry Andric : Name[20]; 3411*0fca6ea1SDimitry Andric 3412*0fca6ea1SDimitry Andric Intrinsic::ID IID; 3413*0fca6ea1SDimitry Andric if (IsVariable && Name[17] != '.') { 3414*0fca6ea1SDimitry Andric if (Size == 'd' && Name[17] == '2') // avx512.mask.psrlv2.di 3415*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx2_psrlv_q; 3416*0fca6ea1SDimitry Andric else if (Size == 'd' && Name[17] == '4') // avx512.mask.psrlv4.di 3417*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx2_psrlv_q_256; 3418*0fca6ea1SDimitry Andric else if (Size == 's' && Name[17] == '4') // avx512.mask.psrlv4.si 3419*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx2_psrlv_d; 3420*0fca6ea1SDimitry Andric else if (Size == 's' && Name[17] == '8') // avx512.mask.psrlv8.si 3421*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx2_psrlv_d_256; 3422*0fca6ea1SDimitry Andric else if (Size == 'h' && Name[17] == '8') // avx512.mask.psrlv8.hi 3423*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_psrlv_w_128; 3424*0fca6ea1SDimitry Andric else if (Size == 'h' && Name[17] == '1') // avx512.mask.psrlv16.hi 3425*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_psrlv_w_256; 3426*0fca6ea1SDimitry Andric else if (Name[17] == '3' && Name[18] == '2') // avx512.mask.psrlv32hi 3427*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_psrlv_w_512; 3428*0fca6ea1SDimitry Andric else 3429*0fca6ea1SDimitry Andric llvm_unreachable("Unexpected size"); 3430*0fca6ea1SDimitry Andric } else if (Name.ends_with(".128")) { 3431*0fca6ea1SDimitry Andric if (Size == 'd') // avx512.mask.psrl.d.128, avx512.mask.psrl.di.128 3432*0fca6ea1SDimitry Andric IID = IsImmediate ? Intrinsic::x86_sse2_psrli_d 3433*0fca6ea1SDimitry Andric : Intrinsic::x86_sse2_psrl_d; 3434*0fca6ea1SDimitry Andric else if (Size == 'q') // avx512.mask.psrl.q.128, avx512.mask.psrl.qi.128 3435*0fca6ea1SDimitry Andric IID = IsImmediate ? Intrinsic::x86_sse2_psrli_q 3436*0fca6ea1SDimitry Andric : Intrinsic::x86_sse2_psrl_q; 3437*0fca6ea1SDimitry Andric else if (Size == 'w') // avx512.mask.psrl.w.128, avx512.mask.psrl.wi.128 3438*0fca6ea1SDimitry Andric IID = IsImmediate ? Intrinsic::x86_sse2_psrli_w 3439*0fca6ea1SDimitry Andric : Intrinsic::x86_sse2_psrl_w; 3440*0fca6ea1SDimitry Andric else 3441*0fca6ea1SDimitry Andric llvm_unreachable("Unexpected size"); 3442*0fca6ea1SDimitry Andric } else if (Name.ends_with(".256")) { 3443*0fca6ea1SDimitry Andric if (Size == 'd') // avx512.mask.psrl.d.256, avx512.mask.psrl.di.256 3444*0fca6ea1SDimitry Andric IID = IsImmediate ? Intrinsic::x86_avx2_psrli_d 3445*0fca6ea1SDimitry Andric : Intrinsic::x86_avx2_psrl_d; 3446*0fca6ea1SDimitry Andric else if (Size == 'q') // avx512.mask.psrl.q.256, avx512.mask.psrl.qi.256 3447*0fca6ea1SDimitry Andric IID = IsImmediate ? Intrinsic::x86_avx2_psrli_q 3448*0fca6ea1SDimitry Andric : Intrinsic::x86_avx2_psrl_q; 3449*0fca6ea1SDimitry Andric else if (Size == 'w') // avx512.mask.psrl.w.256, avx512.mask.psrl.wi.256 3450*0fca6ea1SDimitry Andric IID = IsImmediate ? Intrinsic::x86_avx2_psrli_w 3451*0fca6ea1SDimitry Andric : Intrinsic::x86_avx2_psrl_w; 3452*0fca6ea1SDimitry Andric else 3453*0fca6ea1SDimitry Andric llvm_unreachable("Unexpected size"); 3454*0fca6ea1SDimitry Andric } else { 3455*0fca6ea1SDimitry Andric if (Size == 'd') // psrl.di.512, psrli.d, psrl.d, psrl.d.512 3456*0fca6ea1SDimitry Andric IID = IsImmediate ? Intrinsic::x86_avx512_psrli_d_512 3457*0fca6ea1SDimitry Andric : IsVariable ? Intrinsic::x86_avx512_psrlv_d_512 3458*0fca6ea1SDimitry Andric : Intrinsic::x86_avx512_psrl_d_512; 3459*0fca6ea1SDimitry Andric else if (Size == 'q') // psrl.qi.512, psrli.q, psrl.q, psrl.q.512 3460*0fca6ea1SDimitry Andric IID = IsImmediate ? Intrinsic::x86_avx512_psrli_q_512 3461*0fca6ea1SDimitry Andric : IsVariable ? Intrinsic::x86_avx512_psrlv_q_512 3462*0fca6ea1SDimitry Andric : Intrinsic::x86_avx512_psrl_q_512; 3463*0fca6ea1SDimitry Andric else if (Size == 'w') // psrl.wi.512, psrli.w, psrl.w) 3464*0fca6ea1SDimitry Andric IID = IsImmediate ? Intrinsic::x86_avx512_psrli_w_512 3465*0fca6ea1SDimitry Andric : Intrinsic::x86_avx512_psrl_w_512; 3466*0fca6ea1SDimitry Andric else 3467*0fca6ea1SDimitry Andric llvm_unreachable("Unexpected size"); 3468*0fca6ea1SDimitry Andric } 3469*0fca6ea1SDimitry Andric 3470*0fca6ea1SDimitry Andric Rep = upgradeX86MaskedShift(Builder, *CI, IID); 3471*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.psra")) { 3472*0fca6ea1SDimitry Andric bool IsImmediate = Name[16] == 'i' || (Name.size() > 18 && Name[18] == 'i'); 3473*0fca6ea1SDimitry Andric bool IsVariable = Name[16] == 'v'; 3474*0fca6ea1SDimitry Andric char Size = Name[16] == '.' ? Name[17] 3475*0fca6ea1SDimitry Andric : Name[17] == '.' ? Name[18] 3476*0fca6ea1SDimitry Andric : Name[18] == '.' ? Name[19] 3477*0fca6ea1SDimitry Andric : Name[20]; 3478*0fca6ea1SDimitry Andric 3479*0fca6ea1SDimitry Andric Intrinsic::ID IID; 3480*0fca6ea1SDimitry Andric if (IsVariable && Name[17] != '.') { 3481*0fca6ea1SDimitry Andric if (Size == 's' && Name[17] == '4') // avx512.mask.psrav4.si 3482*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx2_psrav_d; 3483*0fca6ea1SDimitry Andric else if (Size == 's' && Name[17] == '8') // avx512.mask.psrav8.si 3484*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx2_psrav_d_256; 3485*0fca6ea1SDimitry Andric else if (Size == 'h' && Name[17] == '8') // avx512.mask.psrav8.hi 3486*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_psrav_w_128; 3487*0fca6ea1SDimitry Andric else if (Size == 'h' && Name[17] == '1') // avx512.mask.psrav16.hi 3488*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_psrav_w_256; 3489*0fca6ea1SDimitry Andric else if (Name[17] == '3' && Name[18] == '2') // avx512.mask.psrav32hi 3490*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_psrav_w_512; 3491*0fca6ea1SDimitry Andric else 3492*0fca6ea1SDimitry Andric llvm_unreachable("Unexpected size"); 3493*0fca6ea1SDimitry Andric } else if (Name.ends_with(".128")) { 3494*0fca6ea1SDimitry Andric if (Size == 'd') // avx512.mask.psra.d.128, avx512.mask.psra.di.128 3495*0fca6ea1SDimitry Andric IID = IsImmediate ? Intrinsic::x86_sse2_psrai_d 3496*0fca6ea1SDimitry Andric : Intrinsic::x86_sse2_psra_d; 3497*0fca6ea1SDimitry Andric else if (Size == 'q') // avx512.mask.psra.q.128, avx512.mask.psra.qi.128 3498*0fca6ea1SDimitry Andric IID = IsImmediate ? Intrinsic::x86_avx512_psrai_q_128 3499*0fca6ea1SDimitry Andric : IsVariable ? Intrinsic::x86_avx512_psrav_q_128 3500*0fca6ea1SDimitry Andric : Intrinsic::x86_avx512_psra_q_128; 3501*0fca6ea1SDimitry Andric else if (Size == 'w') // avx512.mask.psra.w.128, avx512.mask.psra.wi.128 3502*0fca6ea1SDimitry Andric IID = IsImmediate ? Intrinsic::x86_sse2_psrai_w 3503*0fca6ea1SDimitry Andric : Intrinsic::x86_sse2_psra_w; 3504*0fca6ea1SDimitry Andric else 3505*0fca6ea1SDimitry Andric llvm_unreachable("Unexpected size"); 3506*0fca6ea1SDimitry Andric } else if (Name.ends_with(".256")) { 3507*0fca6ea1SDimitry Andric if (Size == 'd') // avx512.mask.psra.d.256, avx512.mask.psra.di.256 3508*0fca6ea1SDimitry Andric IID = IsImmediate ? Intrinsic::x86_avx2_psrai_d 3509*0fca6ea1SDimitry Andric : Intrinsic::x86_avx2_psra_d; 3510*0fca6ea1SDimitry Andric else if (Size == 'q') // avx512.mask.psra.q.256, avx512.mask.psra.qi.256 3511*0fca6ea1SDimitry Andric IID = IsImmediate ? Intrinsic::x86_avx512_psrai_q_256 3512*0fca6ea1SDimitry Andric : IsVariable ? Intrinsic::x86_avx512_psrav_q_256 3513*0fca6ea1SDimitry Andric : Intrinsic::x86_avx512_psra_q_256; 3514*0fca6ea1SDimitry Andric else if (Size == 'w') // avx512.mask.psra.w.256, avx512.mask.psra.wi.256 3515*0fca6ea1SDimitry Andric IID = IsImmediate ? Intrinsic::x86_avx2_psrai_w 3516*0fca6ea1SDimitry Andric : Intrinsic::x86_avx2_psra_w; 3517*0fca6ea1SDimitry Andric else 3518*0fca6ea1SDimitry Andric llvm_unreachable("Unexpected size"); 3519*0fca6ea1SDimitry Andric } else { 3520*0fca6ea1SDimitry Andric if (Size == 'd') // psra.di.512, psrai.d, psra.d, psrav.d.512 3521*0fca6ea1SDimitry Andric IID = IsImmediate ? Intrinsic::x86_avx512_psrai_d_512 3522*0fca6ea1SDimitry Andric : IsVariable ? Intrinsic::x86_avx512_psrav_d_512 3523*0fca6ea1SDimitry Andric : Intrinsic::x86_avx512_psra_d_512; 3524*0fca6ea1SDimitry Andric else if (Size == 'q') // psra.qi.512, psrai.q, psra.q 3525*0fca6ea1SDimitry Andric IID = IsImmediate ? Intrinsic::x86_avx512_psrai_q_512 3526*0fca6ea1SDimitry Andric : IsVariable ? Intrinsic::x86_avx512_psrav_q_512 3527*0fca6ea1SDimitry Andric : Intrinsic::x86_avx512_psra_q_512; 3528*0fca6ea1SDimitry Andric else if (Size == 'w') // psra.wi.512, psrai.w, psra.w 3529*0fca6ea1SDimitry Andric IID = IsImmediate ? Intrinsic::x86_avx512_psrai_w_512 3530*0fca6ea1SDimitry Andric : Intrinsic::x86_avx512_psra_w_512; 3531*0fca6ea1SDimitry Andric else 3532*0fca6ea1SDimitry Andric llvm_unreachable("Unexpected size"); 3533*0fca6ea1SDimitry Andric } 3534*0fca6ea1SDimitry Andric 3535*0fca6ea1SDimitry Andric Rep = upgradeX86MaskedShift(Builder, *CI, IID); 3536*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.move.s")) { 3537*0fca6ea1SDimitry Andric Rep = upgradeMaskedMove(Builder, *CI); 3538*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.cvtmask2")) { 3539*0fca6ea1SDimitry Andric Rep = upgradeMaskToInt(Builder, *CI); 3540*0fca6ea1SDimitry Andric } else if (Name.ends_with(".movntdqa")) { 3541*0fca6ea1SDimitry Andric MDNode *Node = MDNode::get( 3542*0fca6ea1SDimitry Andric C, ConstantAsMetadata::get(ConstantInt::get(Type::getInt32Ty(C), 1))); 3543*0fca6ea1SDimitry Andric 3544*0fca6ea1SDimitry Andric Value *Ptr = CI->getArgOperand(0); 3545*0fca6ea1SDimitry Andric 3546*0fca6ea1SDimitry Andric // Convert the type of the pointer to a pointer to the stored type. 3547*0fca6ea1SDimitry Andric Value *BC = Builder.CreateBitCast( 3548*0fca6ea1SDimitry Andric Ptr, PointerType::getUnqual(CI->getType()), "cast"); 3549*0fca6ea1SDimitry Andric LoadInst *LI = Builder.CreateAlignedLoad( 3550*0fca6ea1SDimitry Andric CI->getType(), BC, 3551*0fca6ea1SDimitry Andric Align(CI->getType()->getPrimitiveSizeInBits().getFixedValue() / 8)); 3552*0fca6ea1SDimitry Andric LI->setMetadata(LLVMContext::MD_nontemporal, Node); 3553*0fca6ea1SDimitry Andric Rep = LI; 3554*0fca6ea1SDimitry Andric } else if (Name.starts_with("fma.vfmadd.") || 3555*0fca6ea1SDimitry Andric Name.starts_with("fma.vfmsub.") || 3556*0fca6ea1SDimitry Andric Name.starts_with("fma.vfnmadd.") || 3557*0fca6ea1SDimitry Andric Name.starts_with("fma.vfnmsub.")) { 3558*0fca6ea1SDimitry Andric bool NegMul = Name[6] == 'n'; 3559*0fca6ea1SDimitry Andric bool NegAcc = NegMul ? Name[8] == 's' : Name[7] == 's'; 3560*0fca6ea1SDimitry Andric bool IsScalar = NegMul ? Name[12] == 's' : Name[11] == 's'; 3561*0fca6ea1SDimitry Andric 3562*0fca6ea1SDimitry Andric Value *Ops[] = {CI->getArgOperand(0), CI->getArgOperand(1), 3563*0fca6ea1SDimitry Andric CI->getArgOperand(2)}; 3564*0fca6ea1SDimitry Andric 3565*0fca6ea1SDimitry Andric if (IsScalar) { 3566*0fca6ea1SDimitry Andric Ops[0] = Builder.CreateExtractElement(Ops[0], (uint64_t)0); 3567*0fca6ea1SDimitry Andric Ops[1] = Builder.CreateExtractElement(Ops[1], (uint64_t)0); 3568*0fca6ea1SDimitry Andric Ops[2] = Builder.CreateExtractElement(Ops[2], (uint64_t)0); 3569*0fca6ea1SDimitry Andric } 3570*0fca6ea1SDimitry Andric 3571*0fca6ea1SDimitry Andric if (NegMul && !IsScalar) 3572*0fca6ea1SDimitry Andric Ops[0] = Builder.CreateFNeg(Ops[0]); 3573*0fca6ea1SDimitry Andric if (NegMul && IsScalar) 3574*0fca6ea1SDimitry Andric Ops[1] = Builder.CreateFNeg(Ops[1]); 3575*0fca6ea1SDimitry Andric if (NegAcc) 3576*0fca6ea1SDimitry Andric Ops[2] = Builder.CreateFNeg(Ops[2]); 3577*0fca6ea1SDimitry Andric 3578*0fca6ea1SDimitry Andric Rep = Builder.CreateCall(Intrinsic::getDeclaration(CI->getModule(), 3579*0fca6ea1SDimitry Andric Intrinsic::fma, 3580*0fca6ea1SDimitry Andric Ops[0]->getType()), 3581*0fca6ea1SDimitry Andric Ops); 3582*0fca6ea1SDimitry Andric 3583*0fca6ea1SDimitry Andric if (IsScalar) 3584*0fca6ea1SDimitry Andric Rep = Builder.CreateInsertElement(CI->getArgOperand(0), Rep, (uint64_t)0); 3585*0fca6ea1SDimitry Andric } else if (Name.starts_with("fma4.vfmadd.s")) { 3586*0fca6ea1SDimitry Andric Value *Ops[] = {CI->getArgOperand(0), CI->getArgOperand(1), 3587*0fca6ea1SDimitry Andric CI->getArgOperand(2)}; 3588*0fca6ea1SDimitry Andric 3589*0fca6ea1SDimitry Andric Ops[0] = Builder.CreateExtractElement(Ops[0], (uint64_t)0); 3590*0fca6ea1SDimitry Andric Ops[1] = Builder.CreateExtractElement(Ops[1], (uint64_t)0); 3591*0fca6ea1SDimitry Andric Ops[2] = Builder.CreateExtractElement(Ops[2], (uint64_t)0); 3592*0fca6ea1SDimitry Andric 3593*0fca6ea1SDimitry Andric Rep = Builder.CreateCall(Intrinsic::getDeclaration(CI->getModule(), 3594*0fca6ea1SDimitry Andric Intrinsic::fma, 3595*0fca6ea1SDimitry Andric Ops[0]->getType()), 3596*0fca6ea1SDimitry Andric Ops); 3597*0fca6ea1SDimitry Andric 3598*0fca6ea1SDimitry Andric Rep = Builder.CreateInsertElement(Constant::getNullValue(CI->getType()), 3599*0fca6ea1SDimitry Andric Rep, (uint64_t)0); 3600*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.vfmadd.s") || 3601*0fca6ea1SDimitry Andric Name.starts_with("avx512.maskz.vfmadd.s") || 3602*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask3.vfmadd.s") || 3603*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask3.vfmsub.s") || 3604*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask3.vfnmsub.s")) { 3605*0fca6ea1SDimitry Andric bool IsMask3 = Name[11] == '3'; 3606*0fca6ea1SDimitry Andric bool IsMaskZ = Name[11] == 'z'; 3607*0fca6ea1SDimitry Andric // Drop the "avx512.mask." to make it easier. 3608*0fca6ea1SDimitry Andric Name = Name.drop_front(IsMask3 || IsMaskZ ? 13 : 12); 3609*0fca6ea1SDimitry Andric bool NegMul = Name[2] == 'n'; 3610*0fca6ea1SDimitry Andric bool NegAcc = NegMul ? Name[4] == 's' : Name[3] == 's'; 3611*0fca6ea1SDimitry Andric 3612*0fca6ea1SDimitry Andric Value *A = CI->getArgOperand(0); 3613*0fca6ea1SDimitry Andric Value *B = CI->getArgOperand(1); 3614*0fca6ea1SDimitry Andric Value *C = CI->getArgOperand(2); 3615*0fca6ea1SDimitry Andric 3616*0fca6ea1SDimitry Andric if (NegMul && (IsMask3 || IsMaskZ)) 3617*0fca6ea1SDimitry Andric A = Builder.CreateFNeg(A); 3618*0fca6ea1SDimitry Andric if (NegMul && !(IsMask3 || IsMaskZ)) 3619*0fca6ea1SDimitry Andric B = Builder.CreateFNeg(B); 3620*0fca6ea1SDimitry Andric if (NegAcc) 3621*0fca6ea1SDimitry Andric C = Builder.CreateFNeg(C); 3622*0fca6ea1SDimitry Andric 3623*0fca6ea1SDimitry Andric A = Builder.CreateExtractElement(A, (uint64_t)0); 3624*0fca6ea1SDimitry Andric B = Builder.CreateExtractElement(B, (uint64_t)0); 3625*0fca6ea1SDimitry Andric C = Builder.CreateExtractElement(C, (uint64_t)0); 3626*0fca6ea1SDimitry Andric 3627*0fca6ea1SDimitry Andric if (!isa<ConstantInt>(CI->getArgOperand(4)) || 3628*0fca6ea1SDimitry Andric cast<ConstantInt>(CI->getArgOperand(4))->getZExtValue() != 4) { 3629*0fca6ea1SDimitry Andric Value *Ops[] = {A, B, C, CI->getArgOperand(4)}; 3630*0fca6ea1SDimitry Andric 3631*0fca6ea1SDimitry Andric Intrinsic::ID IID; 3632*0fca6ea1SDimitry Andric if (Name.back() == 'd') 3633*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_vfmadd_f64; 3634*0fca6ea1SDimitry Andric else 3635*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_vfmadd_f32; 3636*0fca6ea1SDimitry Andric Function *FMA = Intrinsic::getDeclaration(CI->getModule(), IID); 3637*0fca6ea1SDimitry Andric Rep = Builder.CreateCall(FMA, Ops); 3638*0fca6ea1SDimitry Andric } else { 3639*0fca6ea1SDimitry Andric Function *FMA = Intrinsic::getDeclaration(CI->getModule(), Intrinsic::fma, 3640*0fca6ea1SDimitry Andric A->getType()); 3641*0fca6ea1SDimitry Andric Rep = Builder.CreateCall(FMA, {A, B, C}); 3642*0fca6ea1SDimitry Andric } 3643*0fca6ea1SDimitry Andric 3644*0fca6ea1SDimitry Andric Value *PassThru = IsMaskZ ? Constant::getNullValue(Rep->getType()) 3645*0fca6ea1SDimitry Andric : IsMask3 ? C 3646*0fca6ea1SDimitry Andric : A; 3647*0fca6ea1SDimitry Andric 3648*0fca6ea1SDimitry Andric // For Mask3 with NegAcc, we need to create a new extractelement that 3649*0fca6ea1SDimitry Andric // avoids the negation above. 3650*0fca6ea1SDimitry Andric if (NegAcc && IsMask3) 3651*0fca6ea1SDimitry Andric PassThru = 3652*0fca6ea1SDimitry Andric Builder.CreateExtractElement(CI->getArgOperand(2), (uint64_t)0); 3653*0fca6ea1SDimitry Andric 3654*0fca6ea1SDimitry Andric Rep = emitX86ScalarSelect(Builder, CI->getArgOperand(3), Rep, PassThru); 3655*0fca6ea1SDimitry Andric Rep = Builder.CreateInsertElement(CI->getArgOperand(IsMask3 ? 2 : 0), Rep, 3656*0fca6ea1SDimitry Andric (uint64_t)0); 3657*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.vfmadd.p") || 3658*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.vfnmadd.p") || 3659*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.vfnmsub.p") || 3660*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask3.vfmadd.p") || 3661*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask3.vfmsub.p") || 3662*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask3.vfnmsub.p") || 3663*0fca6ea1SDimitry Andric Name.starts_with("avx512.maskz.vfmadd.p")) { 3664*0fca6ea1SDimitry Andric bool IsMask3 = Name[11] == '3'; 3665*0fca6ea1SDimitry Andric bool IsMaskZ = Name[11] == 'z'; 3666*0fca6ea1SDimitry Andric // Drop the "avx512.mask." to make it easier. 3667*0fca6ea1SDimitry Andric Name = Name.drop_front(IsMask3 || IsMaskZ ? 13 : 12); 3668*0fca6ea1SDimitry Andric bool NegMul = Name[2] == 'n'; 3669*0fca6ea1SDimitry Andric bool NegAcc = NegMul ? Name[4] == 's' : Name[3] == 's'; 3670*0fca6ea1SDimitry Andric 3671*0fca6ea1SDimitry Andric Value *A = CI->getArgOperand(0); 3672*0fca6ea1SDimitry Andric Value *B = CI->getArgOperand(1); 3673*0fca6ea1SDimitry Andric Value *C = CI->getArgOperand(2); 3674*0fca6ea1SDimitry Andric 3675*0fca6ea1SDimitry Andric if (NegMul && (IsMask3 || IsMaskZ)) 3676*0fca6ea1SDimitry Andric A = Builder.CreateFNeg(A); 3677*0fca6ea1SDimitry Andric if (NegMul && !(IsMask3 || IsMaskZ)) 3678*0fca6ea1SDimitry Andric B = Builder.CreateFNeg(B); 3679*0fca6ea1SDimitry Andric if (NegAcc) 3680*0fca6ea1SDimitry Andric C = Builder.CreateFNeg(C); 3681*0fca6ea1SDimitry Andric 3682*0fca6ea1SDimitry Andric if (CI->arg_size() == 5 && 3683*0fca6ea1SDimitry Andric (!isa<ConstantInt>(CI->getArgOperand(4)) || 3684*0fca6ea1SDimitry Andric cast<ConstantInt>(CI->getArgOperand(4))->getZExtValue() != 4)) { 3685*0fca6ea1SDimitry Andric Intrinsic::ID IID; 3686*0fca6ea1SDimitry Andric // Check the character before ".512" in string. 3687*0fca6ea1SDimitry Andric if (Name[Name.size() - 5] == 's') 3688*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_vfmadd_ps_512; 3689*0fca6ea1SDimitry Andric else 3690*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_vfmadd_pd_512; 3691*0fca6ea1SDimitry Andric 3692*0fca6ea1SDimitry Andric Rep = Builder.CreateCall(Intrinsic::getDeclaration(F->getParent(), IID), 3693*0fca6ea1SDimitry Andric {A, B, C, CI->getArgOperand(4)}); 3694*0fca6ea1SDimitry Andric } else { 3695*0fca6ea1SDimitry Andric Function *FMA = Intrinsic::getDeclaration(CI->getModule(), Intrinsic::fma, 3696*0fca6ea1SDimitry Andric A->getType()); 3697*0fca6ea1SDimitry Andric Rep = Builder.CreateCall(FMA, {A, B, C}); 3698*0fca6ea1SDimitry Andric } 3699*0fca6ea1SDimitry Andric 3700*0fca6ea1SDimitry Andric Value *PassThru = IsMaskZ ? llvm::Constant::getNullValue(CI->getType()) 3701*0fca6ea1SDimitry Andric : IsMask3 ? CI->getArgOperand(2) 3702*0fca6ea1SDimitry Andric : CI->getArgOperand(0); 3703*0fca6ea1SDimitry Andric 3704*0fca6ea1SDimitry Andric Rep = emitX86Select(Builder, CI->getArgOperand(3), Rep, PassThru); 3705*0fca6ea1SDimitry Andric } else if (Name.starts_with("fma.vfmsubadd.p")) { 3706*0fca6ea1SDimitry Andric unsigned VecWidth = CI->getType()->getPrimitiveSizeInBits(); 3707*0fca6ea1SDimitry Andric unsigned EltWidth = CI->getType()->getScalarSizeInBits(); 3708*0fca6ea1SDimitry Andric Intrinsic::ID IID; 3709*0fca6ea1SDimitry Andric if (VecWidth == 128 && EltWidth == 32) 3710*0fca6ea1SDimitry Andric IID = Intrinsic::x86_fma_vfmaddsub_ps; 3711*0fca6ea1SDimitry Andric else if (VecWidth == 256 && EltWidth == 32) 3712*0fca6ea1SDimitry Andric IID = Intrinsic::x86_fma_vfmaddsub_ps_256; 3713*0fca6ea1SDimitry Andric else if (VecWidth == 128 && EltWidth == 64) 3714*0fca6ea1SDimitry Andric IID = Intrinsic::x86_fma_vfmaddsub_pd; 3715*0fca6ea1SDimitry Andric else if (VecWidth == 256 && EltWidth == 64) 3716*0fca6ea1SDimitry Andric IID = Intrinsic::x86_fma_vfmaddsub_pd_256; 3717*0fca6ea1SDimitry Andric else 3718*0fca6ea1SDimitry Andric llvm_unreachable("Unexpected intrinsic"); 3719*0fca6ea1SDimitry Andric 3720*0fca6ea1SDimitry Andric Value *Ops[] = {CI->getArgOperand(0), CI->getArgOperand(1), 3721*0fca6ea1SDimitry Andric CI->getArgOperand(2)}; 3722*0fca6ea1SDimitry Andric Ops[2] = Builder.CreateFNeg(Ops[2]); 3723*0fca6ea1SDimitry Andric Rep = 3724*0fca6ea1SDimitry Andric Builder.CreateCall(Intrinsic::getDeclaration(F->getParent(), IID), Ops); 3725*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.vfmaddsub.p") || 3726*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask3.vfmaddsub.p") || 3727*0fca6ea1SDimitry Andric Name.starts_with("avx512.maskz.vfmaddsub.p") || 3728*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask3.vfmsubadd.p")) { 3729*0fca6ea1SDimitry Andric bool IsMask3 = Name[11] == '3'; 3730*0fca6ea1SDimitry Andric bool IsMaskZ = Name[11] == 'z'; 3731*0fca6ea1SDimitry Andric // Drop the "avx512.mask." to make it easier. 3732*0fca6ea1SDimitry Andric Name = Name.drop_front(IsMask3 || IsMaskZ ? 13 : 12); 3733*0fca6ea1SDimitry Andric bool IsSubAdd = Name[3] == 's'; 3734*0fca6ea1SDimitry Andric if (CI->arg_size() == 5) { 3735*0fca6ea1SDimitry Andric Intrinsic::ID IID; 3736*0fca6ea1SDimitry Andric // Check the character before ".512" in string. 3737*0fca6ea1SDimitry Andric if (Name[Name.size() - 5] == 's') 3738*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_vfmaddsub_ps_512; 3739*0fca6ea1SDimitry Andric else 3740*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_vfmaddsub_pd_512; 3741*0fca6ea1SDimitry Andric 3742*0fca6ea1SDimitry Andric Value *Ops[] = {CI->getArgOperand(0), CI->getArgOperand(1), 3743*0fca6ea1SDimitry Andric CI->getArgOperand(2), CI->getArgOperand(4)}; 3744*0fca6ea1SDimitry Andric if (IsSubAdd) 3745*0fca6ea1SDimitry Andric Ops[2] = Builder.CreateFNeg(Ops[2]); 3746*0fca6ea1SDimitry Andric 3747*0fca6ea1SDimitry Andric Rep = Builder.CreateCall(Intrinsic::getDeclaration(F->getParent(), IID), 3748*0fca6ea1SDimitry Andric Ops); 3749*0fca6ea1SDimitry Andric } else { 3750*0fca6ea1SDimitry Andric int NumElts = cast<FixedVectorType>(CI->getType())->getNumElements(); 3751*0fca6ea1SDimitry Andric 3752*0fca6ea1SDimitry Andric Value *Ops[] = {CI->getArgOperand(0), CI->getArgOperand(1), 3753*0fca6ea1SDimitry Andric CI->getArgOperand(2)}; 3754*0fca6ea1SDimitry Andric 3755*0fca6ea1SDimitry Andric Function *FMA = Intrinsic::getDeclaration(CI->getModule(), Intrinsic::fma, 3756*0fca6ea1SDimitry Andric Ops[0]->getType()); 3757*0fca6ea1SDimitry Andric Value *Odd = Builder.CreateCall(FMA, Ops); 3758*0fca6ea1SDimitry Andric Ops[2] = Builder.CreateFNeg(Ops[2]); 3759*0fca6ea1SDimitry Andric Value *Even = Builder.CreateCall(FMA, Ops); 3760*0fca6ea1SDimitry Andric 3761*0fca6ea1SDimitry Andric if (IsSubAdd) 3762*0fca6ea1SDimitry Andric std::swap(Even, Odd); 3763*0fca6ea1SDimitry Andric 3764*0fca6ea1SDimitry Andric SmallVector<int, 32> Idxs(NumElts); 3765*0fca6ea1SDimitry Andric for (int i = 0; i != NumElts; ++i) 3766*0fca6ea1SDimitry Andric Idxs[i] = i + (i % 2) * NumElts; 3767*0fca6ea1SDimitry Andric 3768*0fca6ea1SDimitry Andric Rep = Builder.CreateShuffleVector(Even, Odd, Idxs); 3769*0fca6ea1SDimitry Andric } 3770*0fca6ea1SDimitry Andric 3771*0fca6ea1SDimitry Andric Value *PassThru = IsMaskZ ? llvm::Constant::getNullValue(CI->getType()) 3772*0fca6ea1SDimitry Andric : IsMask3 ? CI->getArgOperand(2) 3773*0fca6ea1SDimitry Andric : CI->getArgOperand(0); 3774*0fca6ea1SDimitry Andric 3775*0fca6ea1SDimitry Andric Rep = emitX86Select(Builder, CI->getArgOperand(3), Rep, PassThru); 3776*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.pternlog.") || 3777*0fca6ea1SDimitry Andric Name.starts_with("avx512.maskz.pternlog.")) { 3778*0fca6ea1SDimitry Andric bool ZeroMask = Name[11] == 'z'; 3779*0fca6ea1SDimitry Andric unsigned VecWidth = CI->getType()->getPrimitiveSizeInBits(); 3780*0fca6ea1SDimitry Andric unsigned EltWidth = CI->getType()->getScalarSizeInBits(); 3781*0fca6ea1SDimitry Andric Intrinsic::ID IID; 3782*0fca6ea1SDimitry Andric if (VecWidth == 128 && EltWidth == 32) 3783*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_pternlog_d_128; 3784*0fca6ea1SDimitry Andric else if (VecWidth == 256 && EltWidth == 32) 3785*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_pternlog_d_256; 3786*0fca6ea1SDimitry Andric else if (VecWidth == 512 && EltWidth == 32) 3787*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_pternlog_d_512; 3788*0fca6ea1SDimitry Andric else if (VecWidth == 128 && EltWidth == 64) 3789*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_pternlog_q_128; 3790*0fca6ea1SDimitry Andric else if (VecWidth == 256 && EltWidth == 64) 3791*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_pternlog_q_256; 3792*0fca6ea1SDimitry Andric else if (VecWidth == 512 && EltWidth == 64) 3793*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_pternlog_q_512; 3794*0fca6ea1SDimitry Andric else 3795*0fca6ea1SDimitry Andric llvm_unreachable("Unexpected intrinsic"); 3796*0fca6ea1SDimitry Andric 3797*0fca6ea1SDimitry Andric Value *Args[] = {CI->getArgOperand(0), CI->getArgOperand(1), 3798*0fca6ea1SDimitry Andric CI->getArgOperand(2), CI->getArgOperand(3)}; 3799*0fca6ea1SDimitry Andric Rep = Builder.CreateCall(Intrinsic::getDeclaration(CI->getModule(), IID), 3800*0fca6ea1SDimitry Andric Args); 3801*0fca6ea1SDimitry Andric Value *PassThru = ZeroMask ? ConstantAggregateZero::get(CI->getType()) 3802*0fca6ea1SDimitry Andric : CI->getArgOperand(0); 3803*0fca6ea1SDimitry Andric Rep = emitX86Select(Builder, CI->getArgOperand(4), Rep, PassThru); 3804*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.vpmadd52") || 3805*0fca6ea1SDimitry Andric Name.starts_with("avx512.maskz.vpmadd52")) { 3806*0fca6ea1SDimitry Andric bool ZeroMask = Name[11] == 'z'; 3807*0fca6ea1SDimitry Andric bool High = Name[20] == 'h' || Name[21] == 'h'; 3808*0fca6ea1SDimitry Andric unsigned VecWidth = CI->getType()->getPrimitiveSizeInBits(); 3809*0fca6ea1SDimitry Andric Intrinsic::ID IID; 3810*0fca6ea1SDimitry Andric if (VecWidth == 128 && !High) 3811*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_vpmadd52l_uq_128; 3812*0fca6ea1SDimitry Andric else if (VecWidth == 256 && !High) 3813*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_vpmadd52l_uq_256; 3814*0fca6ea1SDimitry Andric else if (VecWidth == 512 && !High) 3815*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_vpmadd52l_uq_512; 3816*0fca6ea1SDimitry Andric else if (VecWidth == 128 && High) 3817*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_vpmadd52h_uq_128; 3818*0fca6ea1SDimitry Andric else if (VecWidth == 256 && High) 3819*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_vpmadd52h_uq_256; 3820*0fca6ea1SDimitry Andric else if (VecWidth == 512 && High) 3821*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_vpmadd52h_uq_512; 3822*0fca6ea1SDimitry Andric else 3823*0fca6ea1SDimitry Andric llvm_unreachable("Unexpected intrinsic"); 3824*0fca6ea1SDimitry Andric 3825*0fca6ea1SDimitry Andric Value *Args[] = {CI->getArgOperand(0), CI->getArgOperand(1), 3826*0fca6ea1SDimitry Andric CI->getArgOperand(2)}; 3827*0fca6ea1SDimitry Andric Rep = Builder.CreateCall(Intrinsic::getDeclaration(CI->getModule(), IID), 3828*0fca6ea1SDimitry Andric Args); 3829*0fca6ea1SDimitry Andric Value *PassThru = ZeroMask ? ConstantAggregateZero::get(CI->getType()) 3830*0fca6ea1SDimitry Andric : CI->getArgOperand(0); 3831*0fca6ea1SDimitry Andric Rep = emitX86Select(Builder, CI->getArgOperand(3), Rep, PassThru); 3832*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.vpermi2var.") || 3833*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.vpermt2var.") || 3834*0fca6ea1SDimitry Andric Name.starts_with("avx512.maskz.vpermt2var.")) { 3835*0fca6ea1SDimitry Andric bool ZeroMask = Name[11] == 'z'; 3836*0fca6ea1SDimitry Andric bool IndexForm = Name[17] == 'i'; 3837*0fca6ea1SDimitry Andric Rep = upgradeX86VPERMT2Intrinsics(Builder, *CI, ZeroMask, IndexForm); 3838*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.vpdpbusd.") || 3839*0fca6ea1SDimitry Andric Name.starts_with("avx512.maskz.vpdpbusd.") || 3840*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.vpdpbusds.") || 3841*0fca6ea1SDimitry Andric Name.starts_with("avx512.maskz.vpdpbusds.")) { 3842*0fca6ea1SDimitry Andric bool ZeroMask = Name[11] == 'z'; 3843*0fca6ea1SDimitry Andric bool IsSaturating = Name[ZeroMask ? 21 : 20] == 's'; 3844*0fca6ea1SDimitry Andric unsigned VecWidth = CI->getType()->getPrimitiveSizeInBits(); 3845*0fca6ea1SDimitry Andric Intrinsic::ID IID; 3846*0fca6ea1SDimitry Andric if (VecWidth == 128 && !IsSaturating) 3847*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_vpdpbusd_128; 3848*0fca6ea1SDimitry Andric else if (VecWidth == 256 && !IsSaturating) 3849*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_vpdpbusd_256; 3850*0fca6ea1SDimitry Andric else if (VecWidth == 512 && !IsSaturating) 3851*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_vpdpbusd_512; 3852*0fca6ea1SDimitry Andric else if (VecWidth == 128 && IsSaturating) 3853*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_vpdpbusds_128; 3854*0fca6ea1SDimitry Andric else if (VecWidth == 256 && IsSaturating) 3855*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_vpdpbusds_256; 3856*0fca6ea1SDimitry Andric else if (VecWidth == 512 && IsSaturating) 3857*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_vpdpbusds_512; 3858*0fca6ea1SDimitry Andric else 3859*0fca6ea1SDimitry Andric llvm_unreachable("Unexpected intrinsic"); 3860*0fca6ea1SDimitry Andric 3861*0fca6ea1SDimitry Andric Value *Args[] = {CI->getArgOperand(0), CI->getArgOperand(1), 3862*0fca6ea1SDimitry Andric CI->getArgOperand(2)}; 3863*0fca6ea1SDimitry Andric Rep = Builder.CreateCall(Intrinsic::getDeclaration(CI->getModule(), IID), 3864*0fca6ea1SDimitry Andric Args); 3865*0fca6ea1SDimitry Andric Value *PassThru = ZeroMask ? ConstantAggregateZero::get(CI->getType()) 3866*0fca6ea1SDimitry Andric : CI->getArgOperand(0); 3867*0fca6ea1SDimitry Andric Rep = emitX86Select(Builder, CI->getArgOperand(3), Rep, PassThru); 3868*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.vpdpwssd.") || 3869*0fca6ea1SDimitry Andric Name.starts_with("avx512.maskz.vpdpwssd.") || 3870*0fca6ea1SDimitry Andric Name.starts_with("avx512.mask.vpdpwssds.") || 3871*0fca6ea1SDimitry Andric Name.starts_with("avx512.maskz.vpdpwssds.")) { 3872*0fca6ea1SDimitry Andric bool ZeroMask = Name[11] == 'z'; 3873*0fca6ea1SDimitry Andric bool IsSaturating = Name[ZeroMask ? 21 : 20] == 's'; 3874*0fca6ea1SDimitry Andric unsigned VecWidth = CI->getType()->getPrimitiveSizeInBits(); 3875*0fca6ea1SDimitry Andric Intrinsic::ID IID; 3876*0fca6ea1SDimitry Andric if (VecWidth == 128 && !IsSaturating) 3877*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_vpdpwssd_128; 3878*0fca6ea1SDimitry Andric else if (VecWidth == 256 && !IsSaturating) 3879*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_vpdpwssd_256; 3880*0fca6ea1SDimitry Andric else if (VecWidth == 512 && !IsSaturating) 3881*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_vpdpwssd_512; 3882*0fca6ea1SDimitry Andric else if (VecWidth == 128 && IsSaturating) 3883*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_vpdpwssds_128; 3884*0fca6ea1SDimitry Andric else if (VecWidth == 256 && IsSaturating) 3885*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_vpdpwssds_256; 3886*0fca6ea1SDimitry Andric else if (VecWidth == 512 && IsSaturating) 3887*0fca6ea1SDimitry Andric IID = Intrinsic::x86_avx512_vpdpwssds_512; 3888*0fca6ea1SDimitry Andric else 3889*0fca6ea1SDimitry Andric llvm_unreachable("Unexpected intrinsic"); 3890*0fca6ea1SDimitry Andric 3891*0fca6ea1SDimitry Andric Value *Args[] = {CI->getArgOperand(0), CI->getArgOperand(1), 3892*0fca6ea1SDimitry Andric CI->getArgOperand(2)}; 3893*0fca6ea1SDimitry Andric Rep = Builder.CreateCall(Intrinsic::getDeclaration(CI->getModule(), IID), 3894*0fca6ea1SDimitry Andric Args); 3895*0fca6ea1SDimitry Andric Value *PassThru = ZeroMask ? ConstantAggregateZero::get(CI->getType()) 3896*0fca6ea1SDimitry Andric : CI->getArgOperand(0); 3897*0fca6ea1SDimitry Andric Rep = emitX86Select(Builder, CI->getArgOperand(3), Rep, PassThru); 3898*0fca6ea1SDimitry Andric } else if (Name == "addcarryx.u32" || Name == "addcarryx.u64" || 3899*0fca6ea1SDimitry Andric Name == "addcarry.u32" || Name == "addcarry.u64" || 3900*0fca6ea1SDimitry Andric Name == "subborrow.u32" || Name == "subborrow.u64") { 3901*0fca6ea1SDimitry Andric Intrinsic::ID IID; 3902*0fca6ea1SDimitry Andric if (Name[0] == 'a' && Name.back() == '2') 3903*0fca6ea1SDimitry Andric IID = Intrinsic::x86_addcarry_32; 3904*0fca6ea1SDimitry Andric else if (Name[0] == 'a' && Name.back() == '4') 3905*0fca6ea1SDimitry Andric IID = Intrinsic::x86_addcarry_64; 3906*0fca6ea1SDimitry Andric else if (Name[0] == 's' && Name.back() == '2') 3907*0fca6ea1SDimitry Andric IID = Intrinsic::x86_subborrow_32; 3908*0fca6ea1SDimitry Andric else if (Name[0] == 's' && Name.back() == '4') 3909*0fca6ea1SDimitry Andric IID = Intrinsic::x86_subborrow_64; 3910*0fca6ea1SDimitry Andric else 3911*0fca6ea1SDimitry Andric llvm_unreachable("Unexpected intrinsic"); 3912*0fca6ea1SDimitry Andric 3913*0fca6ea1SDimitry Andric // Make a call with 3 operands. 3914*0fca6ea1SDimitry Andric Value *Args[] = {CI->getArgOperand(0), CI->getArgOperand(1), 3915*0fca6ea1SDimitry Andric CI->getArgOperand(2)}; 3916*0fca6ea1SDimitry Andric Value *NewCall = Builder.CreateCall( 3917*0fca6ea1SDimitry Andric Intrinsic::getDeclaration(CI->getModule(), IID), Args); 3918*0fca6ea1SDimitry Andric 3919*0fca6ea1SDimitry Andric // Extract the second result and store it. 3920*0fca6ea1SDimitry Andric Value *Data = Builder.CreateExtractValue(NewCall, 1); 3921*0fca6ea1SDimitry Andric // Cast the pointer to the right type. 3922*0fca6ea1SDimitry Andric Value *Ptr = Builder.CreateBitCast( 3923*0fca6ea1SDimitry Andric CI->getArgOperand(3), llvm::PointerType::getUnqual(Data->getType())); 3924*0fca6ea1SDimitry Andric Builder.CreateAlignedStore(Data, Ptr, Align(1)); 3925*0fca6ea1SDimitry Andric // Replace the original call result with the first result of the new call. 3926*0fca6ea1SDimitry Andric Value *CF = Builder.CreateExtractValue(NewCall, 0); 3927*0fca6ea1SDimitry Andric 3928*0fca6ea1SDimitry Andric CI->replaceAllUsesWith(CF); 3929*0fca6ea1SDimitry Andric Rep = nullptr; 3930*0fca6ea1SDimitry Andric } else if (Name.starts_with("avx512.mask.") && 3931*0fca6ea1SDimitry Andric upgradeAVX512MaskToSelect(Name, Builder, *CI, Rep)) { 3932*0fca6ea1SDimitry Andric // Rep will be updated by the call in the condition. 3933*0fca6ea1SDimitry Andric } 3934*0fca6ea1SDimitry Andric 3935*0fca6ea1SDimitry Andric return Rep; 3936*0fca6ea1SDimitry Andric } 3937*0fca6ea1SDimitry Andric 39387a6dacacSDimitry Andric static Value *upgradeARMIntrinsicCall(StringRef Name, CallBase *CI, Function *F, 39390eae32dcSDimitry Andric IRBuilder<> &Builder) { 39400eae32dcSDimitry Andric if (Name == "mve.vctp64.old") { 39410eae32dcSDimitry Andric // Replace the old v4i1 vctp64 with a v2i1 vctp and predicate-casts to the 39420eae32dcSDimitry Andric // correct type. 39430eae32dcSDimitry Andric Value *VCTP = Builder.CreateCall( 39440eae32dcSDimitry Andric Intrinsic::getDeclaration(F->getParent(), Intrinsic::arm_mve_vctp64), 39450eae32dcSDimitry Andric CI->getArgOperand(0), CI->getName()); 39460eae32dcSDimitry Andric Value *C1 = Builder.CreateCall( 39470eae32dcSDimitry Andric Intrinsic::getDeclaration( 39480eae32dcSDimitry Andric F->getParent(), Intrinsic::arm_mve_pred_v2i, 39490eae32dcSDimitry Andric {VectorType::get(Builder.getInt1Ty(), 2, false)}), 39500eae32dcSDimitry Andric VCTP); 39510eae32dcSDimitry Andric return Builder.CreateCall( 39520eae32dcSDimitry Andric Intrinsic::getDeclaration( 39530eae32dcSDimitry Andric F->getParent(), Intrinsic::arm_mve_pred_i2v, 39540eae32dcSDimitry Andric {VectorType::get(Builder.getInt1Ty(), 4, false)}), 39550eae32dcSDimitry Andric C1); 39560eae32dcSDimitry Andric } else if (Name == "mve.mull.int.predicated.v2i64.v4i32.v4i1" || 39570eae32dcSDimitry Andric Name == "mve.vqdmull.predicated.v2i64.v4i32.v4i1" || 39580eae32dcSDimitry Andric Name == "mve.vldr.gather.base.predicated.v2i64.v2i64.v4i1" || 39590eae32dcSDimitry Andric Name == "mve.vldr.gather.base.wb.predicated.v2i64.v2i64.v4i1" || 396006c3fb27SDimitry Andric Name == 396106c3fb27SDimitry Andric "mve.vldr.gather.offset.predicated.v2i64.p0i64.v2i64.v4i1" || 396206c3fb27SDimitry Andric Name == "mve.vldr.gather.offset.predicated.v2i64.p0.v2i64.v4i1" || 39630eae32dcSDimitry Andric Name == "mve.vstr.scatter.base.predicated.v2i64.v2i64.v4i1" || 39640eae32dcSDimitry Andric Name == "mve.vstr.scatter.base.wb.predicated.v2i64.v2i64.v4i1" || 396506c3fb27SDimitry Andric Name == 396606c3fb27SDimitry Andric "mve.vstr.scatter.offset.predicated.p0i64.v2i64.v2i64.v4i1" || 396706c3fb27SDimitry Andric Name == "mve.vstr.scatter.offset.predicated.p0.v2i64.v2i64.v4i1" || 39680eae32dcSDimitry Andric Name == "cde.vcx1q.predicated.v2i64.v4i1" || 39690eae32dcSDimitry Andric Name == "cde.vcx1qa.predicated.v2i64.v4i1" || 39700eae32dcSDimitry Andric Name == "cde.vcx2q.predicated.v2i64.v4i1" || 39710eae32dcSDimitry Andric Name == "cde.vcx2qa.predicated.v2i64.v4i1" || 39720eae32dcSDimitry Andric Name == "cde.vcx3q.predicated.v2i64.v4i1" || 39730eae32dcSDimitry Andric Name == "cde.vcx3qa.predicated.v2i64.v4i1") { 39740eae32dcSDimitry Andric std::vector<Type *> Tys; 39750eae32dcSDimitry Andric unsigned ID = CI->getIntrinsicID(); 39760eae32dcSDimitry Andric Type *V2I1Ty = FixedVectorType::get(Builder.getInt1Ty(), 2); 39770eae32dcSDimitry Andric switch (ID) { 39780eae32dcSDimitry Andric case Intrinsic::arm_mve_mull_int_predicated: 39790eae32dcSDimitry Andric case Intrinsic::arm_mve_vqdmull_predicated: 39800eae32dcSDimitry Andric case Intrinsic::arm_mve_vldr_gather_base_predicated: 39810eae32dcSDimitry Andric Tys = {CI->getType(), CI->getOperand(0)->getType(), V2I1Ty}; 39820eae32dcSDimitry Andric break; 39830eae32dcSDimitry Andric case Intrinsic::arm_mve_vldr_gather_base_wb_predicated: 39840eae32dcSDimitry Andric case Intrinsic::arm_mve_vstr_scatter_base_predicated: 39850eae32dcSDimitry Andric case Intrinsic::arm_mve_vstr_scatter_base_wb_predicated: 39860eae32dcSDimitry Andric Tys = {CI->getOperand(0)->getType(), CI->getOperand(0)->getType(), 39870eae32dcSDimitry Andric V2I1Ty}; 39880eae32dcSDimitry Andric break; 39890eae32dcSDimitry Andric case Intrinsic::arm_mve_vldr_gather_offset_predicated: 39900eae32dcSDimitry Andric Tys = {CI->getType(), CI->getOperand(0)->getType(), 39910eae32dcSDimitry Andric CI->getOperand(1)->getType(), V2I1Ty}; 39920eae32dcSDimitry Andric break; 39930eae32dcSDimitry Andric case Intrinsic::arm_mve_vstr_scatter_offset_predicated: 39940eae32dcSDimitry Andric Tys = {CI->getOperand(0)->getType(), CI->getOperand(1)->getType(), 39950eae32dcSDimitry Andric CI->getOperand(2)->getType(), V2I1Ty}; 39960eae32dcSDimitry Andric break; 39970eae32dcSDimitry Andric case Intrinsic::arm_cde_vcx1q_predicated: 39980eae32dcSDimitry Andric case Intrinsic::arm_cde_vcx1qa_predicated: 39990eae32dcSDimitry Andric case Intrinsic::arm_cde_vcx2q_predicated: 40000eae32dcSDimitry Andric case Intrinsic::arm_cde_vcx2qa_predicated: 40010eae32dcSDimitry Andric case Intrinsic::arm_cde_vcx3q_predicated: 40020eae32dcSDimitry Andric case Intrinsic::arm_cde_vcx3qa_predicated: 40030eae32dcSDimitry Andric Tys = {CI->getOperand(1)->getType(), V2I1Ty}; 40040eae32dcSDimitry Andric break; 40050eae32dcSDimitry Andric default: 40060eae32dcSDimitry Andric llvm_unreachable("Unhandled Intrinsic!"); 40070eae32dcSDimitry Andric } 40080eae32dcSDimitry Andric 40090eae32dcSDimitry Andric std::vector<Value *> Ops; 40100eae32dcSDimitry Andric for (Value *Op : CI->args()) { 40110eae32dcSDimitry Andric Type *Ty = Op->getType(); 40120eae32dcSDimitry Andric if (Ty->getScalarSizeInBits() == 1) { 40130eae32dcSDimitry Andric Value *C1 = Builder.CreateCall( 40140eae32dcSDimitry Andric Intrinsic::getDeclaration( 40150eae32dcSDimitry Andric F->getParent(), Intrinsic::arm_mve_pred_v2i, 40160eae32dcSDimitry Andric {VectorType::get(Builder.getInt1Ty(), 4, false)}), 40170eae32dcSDimitry Andric Op); 40180eae32dcSDimitry Andric Op = Builder.CreateCall( 40190eae32dcSDimitry Andric Intrinsic::getDeclaration(F->getParent(), 40200eae32dcSDimitry Andric Intrinsic::arm_mve_pred_i2v, {V2I1Ty}), 40210eae32dcSDimitry Andric C1); 40220eae32dcSDimitry Andric } 40230eae32dcSDimitry Andric Ops.push_back(Op); 40240eae32dcSDimitry Andric } 40250eae32dcSDimitry Andric 40260eae32dcSDimitry Andric Function *Fn = Intrinsic::getDeclaration(F->getParent(), ID, Tys); 40270eae32dcSDimitry Andric return Builder.CreateCall(Fn, Ops, CI->getName()); 40280eae32dcSDimitry Andric } 402981ad6265SDimitry Andric llvm_unreachable("Unknown function for ARM CallBase upgrade."); 40300eae32dcSDimitry Andric } 40310eae32dcSDimitry Andric 4032*0fca6ea1SDimitry Andric // These are expected to have the arguments: 4033*0fca6ea1SDimitry Andric // atomic.intrin (ptr, rmw_value, ordering, scope, isVolatile) 4034*0fca6ea1SDimitry Andric // 4035*0fca6ea1SDimitry Andric // Except for int_amdgcn_ds_fadd_v2bf16 which only has (ptr, rmw_value). 4036*0fca6ea1SDimitry Andric // 40377a6dacacSDimitry Andric static Value *upgradeAMDGCNIntrinsicCall(StringRef Name, CallBase *CI, 403806c3fb27SDimitry Andric Function *F, IRBuilder<> &Builder) { 4039*0fca6ea1SDimitry Andric AtomicRMWInst::BinOp RMWOp = 4040*0fca6ea1SDimitry Andric StringSwitch<AtomicRMWInst::BinOp>(Name) 4041*0fca6ea1SDimitry Andric .StartsWith("ds.fadd", AtomicRMWInst::FAdd) 4042*0fca6ea1SDimitry Andric .StartsWith("ds.fmin", AtomicRMWInst::FMin) 4043*0fca6ea1SDimitry Andric .StartsWith("ds.fmax", AtomicRMWInst::FMax) 4044*0fca6ea1SDimitry Andric .StartsWith("atomic.inc.", AtomicRMWInst::UIncWrap) 4045*0fca6ea1SDimitry Andric .StartsWith("atomic.dec.", AtomicRMWInst::UDecWrap); 4046*0fca6ea1SDimitry Andric 4047*0fca6ea1SDimitry Andric unsigned NumOperands = CI->getNumOperands(); 4048*0fca6ea1SDimitry Andric if (NumOperands < 3) // Malformed bitcode. 404906c3fb27SDimitry Andric return nullptr; 405006c3fb27SDimitry Andric 405106c3fb27SDimitry Andric Value *Ptr = CI->getArgOperand(0); 4052*0fca6ea1SDimitry Andric PointerType *PtrTy = dyn_cast<PointerType>(Ptr->getType()); 4053*0fca6ea1SDimitry Andric if (!PtrTy) // Malformed. 4054*0fca6ea1SDimitry Andric return nullptr; 4055*0fca6ea1SDimitry Andric 405606c3fb27SDimitry Andric Value *Val = CI->getArgOperand(1); 4057*0fca6ea1SDimitry Andric if (Val->getType() != CI->getType()) // Malformed. 4058*0fca6ea1SDimitry Andric return nullptr; 4059*0fca6ea1SDimitry Andric 4060*0fca6ea1SDimitry Andric ConstantInt *OrderArg = nullptr; 4061*0fca6ea1SDimitry Andric bool IsVolatile = false; 4062*0fca6ea1SDimitry Andric 4063*0fca6ea1SDimitry Andric // These should have 5 arguments (plus the callee). A separate version of the 4064*0fca6ea1SDimitry Andric // ds_fadd intrinsic was defined for bf16 which was missing arguments. 4065*0fca6ea1SDimitry Andric if (NumOperands > 3) 4066*0fca6ea1SDimitry Andric OrderArg = dyn_cast<ConstantInt>(CI->getArgOperand(2)); 4067*0fca6ea1SDimitry Andric 4068*0fca6ea1SDimitry Andric // Ignore scope argument at 3 4069*0fca6ea1SDimitry Andric 4070*0fca6ea1SDimitry Andric if (NumOperands > 5) { 407106c3fb27SDimitry Andric ConstantInt *VolatileArg = dyn_cast<ConstantInt>(CI->getArgOperand(4)); 4072*0fca6ea1SDimitry Andric IsVolatile = !VolatileArg || !VolatileArg->isZero(); 4073*0fca6ea1SDimitry Andric } 407406c3fb27SDimitry Andric 407506c3fb27SDimitry Andric AtomicOrdering Order = AtomicOrdering::SequentiallyConsistent; 407606c3fb27SDimitry Andric if (OrderArg && isValidAtomicOrdering(OrderArg->getZExtValue())) 407706c3fb27SDimitry Andric Order = static_cast<AtomicOrdering>(OrderArg->getZExtValue()); 4078*0fca6ea1SDimitry Andric if (Order == AtomicOrdering::NotAtomic || Order == AtomicOrdering::Unordered) 407906c3fb27SDimitry Andric Order = AtomicOrdering::SequentiallyConsistent; 408006c3fb27SDimitry Andric 4081*0fca6ea1SDimitry Andric LLVMContext &Ctx = F->getContext(); 4082*0fca6ea1SDimitry Andric 4083*0fca6ea1SDimitry Andric // Handle the v2bf16 intrinsic which used <2 x i16> instead of <2 x bfloat> 4084*0fca6ea1SDimitry Andric Type *RetTy = CI->getType(); 4085*0fca6ea1SDimitry Andric if (VectorType *VT = dyn_cast<VectorType>(RetTy)) { 4086*0fca6ea1SDimitry Andric if (VT->getElementType()->isIntegerTy(16)) { 4087*0fca6ea1SDimitry Andric VectorType *AsBF16 = 4088*0fca6ea1SDimitry Andric VectorType::get(Type::getBFloatTy(Ctx), VT->getElementCount()); 4089*0fca6ea1SDimitry Andric Val = Builder.CreateBitCast(Val, AsBF16); 4090*0fca6ea1SDimitry Andric } 4091*0fca6ea1SDimitry Andric } 4092*0fca6ea1SDimitry Andric 40935f757f3fSDimitry Andric // The scope argument never really worked correctly. Use agent as the most 40945f757f3fSDimitry Andric // conservative option which should still always produce the instruction. 4095*0fca6ea1SDimitry Andric SyncScope::ID SSID = Ctx.getOrInsertSyncScopeID("agent"); 40965f757f3fSDimitry Andric AtomicRMWInst *RMW = 40975f757f3fSDimitry Andric Builder.CreateAtomicRMW(RMWOp, Ptr, Val, std::nullopt, Order, SSID); 409806c3fb27SDimitry Andric 4099*0fca6ea1SDimitry Andric if (PtrTy->getAddressSpace() != 3) { 4100*0fca6ea1SDimitry Andric RMW->setMetadata("amdgpu.no.fine.grained.memory", 4101*0fca6ea1SDimitry Andric MDNode::get(F->getContext(), {})); 410206c3fb27SDimitry Andric } 410306c3fb27SDimitry Andric 4104*0fca6ea1SDimitry Andric if (IsVolatile) 4105*0fca6ea1SDimitry Andric RMW->setVolatile(true); 4106*0fca6ea1SDimitry Andric 4107*0fca6ea1SDimitry Andric return Builder.CreateBitCast(RMW, RetTy); 4108*0fca6ea1SDimitry Andric } 4109*0fca6ea1SDimitry Andric 4110*0fca6ea1SDimitry Andric /// Helper to unwrap intrinsic call MetadataAsValue operands. 4111*0fca6ea1SDimitry Andric template <typename MDType> 4112*0fca6ea1SDimitry Andric static MDType *unwrapMAVOp(CallBase *CI, unsigned Op) { 4113*0fca6ea1SDimitry Andric if (MetadataAsValue *MAV = dyn_cast<MetadataAsValue>(CI->getArgOperand(Op))) 4114*0fca6ea1SDimitry Andric return dyn_cast<MDType>(MAV->getMetadata()); 4115*0fca6ea1SDimitry Andric return nullptr; 4116*0fca6ea1SDimitry Andric } 4117*0fca6ea1SDimitry Andric 4118*0fca6ea1SDimitry Andric /// Convert debug intrinsic calls to non-instruction debug records. 4119*0fca6ea1SDimitry Andric /// \p Name - Final part of the intrinsic name, e.g. 'value' in llvm.dbg.value. 4120*0fca6ea1SDimitry Andric /// \p CI - The debug intrinsic call. 4121*0fca6ea1SDimitry Andric static void upgradeDbgIntrinsicToDbgRecord(StringRef Name, CallBase *CI) { 4122*0fca6ea1SDimitry Andric DbgRecord *DR = nullptr; 4123*0fca6ea1SDimitry Andric if (Name == "label") { 4124*0fca6ea1SDimitry Andric DR = new DbgLabelRecord(unwrapMAVOp<DILabel>(CI, 0), CI->getDebugLoc()); 4125*0fca6ea1SDimitry Andric } else if (Name == "assign") { 4126*0fca6ea1SDimitry Andric DR = new DbgVariableRecord( 4127*0fca6ea1SDimitry Andric unwrapMAVOp<Metadata>(CI, 0), unwrapMAVOp<DILocalVariable>(CI, 1), 4128*0fca6ea1SDimitry Andric unwrapMAVOp<DIExpression>(CI, 2), unwrapMAVOp<DIAssignID>(CI, 3), 4129*0fca6ea1SDimitry Andric unwrapMAVOp<Metadata>(CI, 4), unwrapMAVOp<DIExpression>(CI, 5), 4130*0fca6ea1SDimitry Andric CI->getDebugLoc()); 4131*0fca6ea1SDimitry Andric } else if (Name == "declare") { 4132*0fca6ea1SDimitry Andric DR = new DbgVariableRecord( 4133*0fca6ea1SDimitry Andric unwrapMAVOp<Metadata>(CI, 0), unwrapMAVOp<DILocalVariable>(CI, 1), 4134*0fca6ea1SDimitry Andric unwrapMAVOp<DIExpression>(CI, 2), CI->getDebugLoc(), 4135*0fca6ea1SDimitry Andric DbgVariableRecord::LocationType::Declare); 4136*0fca6ea1SDimitry Andric } else if (Name == "addr") { 4137*0fca6ea1SDimitry Andric // Upgrade dbg.addr to dbg.value with DW_OP_deref. 4138*0fca6ea1SDimitry Andric DIExpression *Expr = unwrapMAVOp<DIExpression>(CI, 2); 4139*0fca6ea1SDimitry Andric Expr = DIExpression::append(Expr, dwarf::DW_OP_deref); 4140*0fca6ea1SDimitry Andric DR = new DbgVariableRecord(unwrapMAVOp<Metadata>(CI, 0), 4141*0fca6ea1SDimitry Andric unwrapMAVOp<DILocalVariable>(CI, 1), Expr, 4142*0fca6ea1SDimitry Andric CI->getDebugLoc()); 4143*0fca6ea1SDimitry Andric } else if (Name == "value") { 4144*0fca6ea1SDimitry Andric // An old version of dbg.value had an extra offset argument. 4145*0fca6ea1SDimitry Andric unsigned VarOp = 1; 4146*0fca6ea1SDimitry Andric unsigned ExprOp = 2; 4147*0fca6ea1SDimitry Andric if (CI->arg_size() == 4) { 4148*0fca6ea1SDimitry Andric auto *Offset = dyn_cast_or_null<Constant>(CI->getArgOperand(1)); 4149*0fca6ea1SDimitry Andric // Nonzero offset dbg.values get dropped without a replacement. 4150*0fca6ea1SDimitry Andric if (!Offset || !Offset->isZeroValue()) 4151*0fca6ea1SDimitry Andric return; 4152*0fca6ea1SDimitry Andric VarOp = 2; 4153*0fca6ea1SDimitry Andric ExprOp = 3; 4154*0fca6ea1SDimitry Andric } 4155*0fca6ea1SDimitry Andric DR = new DbgVariableRecord( 4156*0fca6ea1SDimitry Andric unwrapMAVOp<Metadata>(CI, 0), unwrapMAVOp<DILocalVariable>(CI, VarOp), 4157*0fca6ea1SDimitry Andric unwrapMAVOp<DIExpression>(CI, ExprOp), CI->getDebugLoc()); 4158*0fca6ea1SDimitry Andric } 4159*0fca6ea1SDimitry Andric assert(DR && "Unhandled intrinsic kind in upgrade to DbgRecord"); 4160*0fca6ea1SDimitry Andric CI->getParent()->insertDbgRecordBefore(DR, CI->getIterator()); 416106c3fb27SDimitry Andric } 416206c3fb27SDimitry Andric 41630b57cec5SDimitry Andric /// Upgrade a call to an old intrinsic. All argument and return casting must be 41640b57cec5SDimitry Andric /// provided to seamlessly integrate with existing context. 416581ad6265SDimitry Andric void llvm::UpgradeIntrinsicCall(CallBase *CI, Function *NewFn) { 4166bdd1243dSDimitry Andric // Note dyn_cast to Function is not quite the same as getCalledFunction, which 4167bdd1243dSDimitry Andric // checks the callee's function type matches. It's likely we need to handle 4168bdd1243dSDimitry Andric // type changes here. 4169bdd1243dSDimitry Andric Function *F = dyn_cast<Function>(CI->getCalledOperand()); 4170bdd1243dSDimitry Andric if (!F) 4171bdd1243dSDimitry Andric return; 4172bdd1243dSDimitry Andric 41730b57cec5SDimitry Andric LLVMContext &C = CI->getContext(); 41740b57cec5SDimitry Andric IRBuilder<> Builder(C); 41750b57cec5SDimitry Andric Builder.SetInsertPoint(CI->getParent(), CI->getIterator()); 41760b57cec5SDimitry Andric 41770b57cec5SDimitry Andric if (!NewFn) { 4178*0fca6ea1SDimitry Andric bool FallthroughToDefaultUpgrade = false; 41790b57cec5SDimitry Andric // Get the Function's name. 41800b57cec5SDimitry Andric StringRef Name = F->getName(); 41810b57cec5SDimitry Andric 41825f757f3fSDimitry Andric assert(Name.starts_with("llvm.") && "Intrinsic doesn't start with 'llvm.'"); 41830b57cec5SDimitry Andric Name = Name.substr(5); 41840b57cec5SDimitry Andric 41857a6dacacSDimitry Andric bool IsX86 = Name.consume_front("x86."); 41867a6dacacSDimitry Andric bool IsNVVM = Name.consume_front("nvvm."); 41877a6dacacSDimitry Andric bool IsARM = Name.consume_front("arm."); 41887a6dacacSDimitry Andric bool IsAMDGCN = Name.consume_front("amdgcn."); 4189*0fca6ea1SDimitry Andric bool IsDbg = Name.consume_front("dbg."); 4190*0fca6ea1SDimitry Andric Value *Rep = nullptr; 41910b57cec5SDimitry Andric 4192*0fca6ea1SDimitry Andric if (!IsX86 && Name == "stackprotectorcheck") { 41930b57cec5SDimitry Andric Rep = nullptr; 41940b57cec5SDimitry Andric } else if (IsNVVM && (Name == "abs.i" || Name == "abs.ll")) { 41950b57cec5SDimitry Andric Value *Arg = CI->getArgOperand(0); 41960b57cec5SDimitry Andric Value *Neg = Builder.CreateNeg(Arg, "neg"); 41970b57cec5SDimitry Andric Value *Cmp = Builder.CreateICmpSGE( 41980b57cec5SDimitry Andric Arg, llvm::Constant::getNullValue(Arg->getType()), "abs.cond"); 41990b57cec5SDimitry Andric Rep = Builder.CreateSelect(Cmp, Arg, Neg, "abs"); 42005f757f3fSDimitry Andric } else if (IsNVVM && (Name.starts_with("atomic.load.add.f32.p") || 42015f757f3fSDimitry Andric Name.starts_with("atomic.load.add.f64.p"))) { 42020b57cec5SDimitry Andric Value *Ptr = CI->getArgOperand(0); 42030b57cec5SDimitry Andric Value *Val = CI->getArgOperand(1); 4204fe6060f1SDimitry Andric Rep = Builder.CreateAtomicRMW(AtomicRMWInst::FAdd, Ptr, Val, MaybeAlign(), 42050b57cec5SDimitry Andric AtomicOrdering::SequentiallyConsistent); 42067a6dacacSDimitry Andric } else if (IsNVVM && Name.consume_front("max.") && 42077a6dacacSDimitry Andric (Name == "s" || Name == "i" || Name == "ll" || Name == "us" || 42087a6dacacSDimitry Andric Name == "ui" || Name == "ull")) { 42090b57cec5SDimitry Andric Value *Arg0 = CI->getArgOperand(0); 42100b57cec5SDimitry Andric Value *Arg1 = CI->getArgOperand(1); 42117a6dacacSDimitry Andric Value *Cmp = Name.starts_with("u") 42120b57cec5SDimitry Andric ? Builder.CreateICmpUGE(Arg0, Arg1, "max.cond") 42130b57cec5SDimitry Andric : Builder.CreateICmpSGE(Arg0, Arg1, "max.cond"); 42140b57cec5SDimitry Andric Rep = Builder.CreateSelect(Cmp, Arg0, Arg1, "max"); 42157a6dacacSDimitry Andric } else if (IsNVVM && Name.consume_front("min.") && 42167a6dacacSDimitry Andric (Name == "s" || Name == "i" || Name == "ll" || Name == "us" || 42177a6dacacSDimitry Andric Name == "ui" || Name == "ull")) { 42180b57cec5SDimitry Andric Value *Arg0 = CI->getArgOperand(0); 42190b57cec5SDimitry Andric Value *Arg1 = CI->getArgOperand(1); 42207a6dacacSDimitry Andric Value *Cmp = Name.starts_with("u") 42210b57cec5SDimitry Andric ? Builder.CreateICmpULE(Arg0, Arg1, "min.cond") 42220b57cec5SDimitry Andric : Builder.CreateICmpSLE(Arg0, Arg1, "min.cond"); 42230b57cec5SDimitry Andric Rep = Builder.CreateSelect(Cmp, Arg0, Arg1, "min"); 42240b57cec5SDimitry Andric } else if (IsNVVM && Name == "clz.ll") { 42257a6dacacSDimitry Andric // llvm.nvvm.clz.ll returns an i32, but llvm.ctlz.i64 returns an i64. 42260b57cec5SDimitry Andric Value *Arg = CI->getArgOperand(0); 42270b57cec5SDimitry Andric Value *Ctlz = Builder.CreateCall( 42280b57cec5SDimitry Andric Intrinsic::getDeclaration(F->getParent(), Intrinsic::ctlz, 42290b57cec5SDimitry Andric {Arg->getType()}), 42300b57cec5SDimitry Andric {Arg, Builder.getFalse()}, "ctlz"); 42310b57cec5SDimitry Andric Rep = Builder.CreateTrunc(Ctlz, Builder.getInt32Ty(), "ctlz.trunc"); 42320b57cec5SDimitry Andric } else if (IsNVVM && Name == "popc.ll") { 42337a6dacacSDimitry Andric // llvm.nvvm.popc.ll returns an i32, but llvm.ctpop.i64 returns an 42340b57cec5SDimitry Andric // i64. 42350b57cec5SDimitry Andric Value *Arg = CI->getArgOperand(0); 42360b57cec5SDimitry Andric Value *Popc = Builder.CreateCall( 42370b57cec5SDimitry Andric Intrinsic::getDeclaration(F->getParent(), Intrinsic::ctpop, 42380b57cec5SDimitry Andric {Arg->getType()}), 42390b57cec5SDimitry Andric Arg, "ctpop"); 42400b57cec5SDimitry Andric Rep = Builder.CreateTrunc(Popc, Builder.getInt32Ty(), "ctpop.trunc"); 424106c3fb27SDimitry Andric } else if (IsNVVM) { 424206c3fb27SDimitry Andric if (Name == "h2f") { 424306c3fb27SDimitry Andric Rep = 424406c3fb27SDimitry Andric Builder.CreateCall(Intrinsic::getDeclaration( 42450b57cec5SDimitry Andric F->getParent(), Intrinsic::convert_from_fp16, 42460b57cec5SDimitry Andric {Builder.getFloatTy()}), 42470b57cec5SDimitry Andric CI->getArgOperand(0), "h2f"); 424806c3fb27SDimitry Andric } else { 42497a6dacacSDimitry Andric Intrinsic::ID IID = shouldUpgradeNVPTXBF16Intrinsic(Name); 425006c3fb27SDimitry Andric if (IID != Intrinsic::not_intrinsic && 425106c3fb27SDimitry Andric !F->getReturnType()->getScalarType()->isBFloatTy()) { 425206c3fb27SDimitry Andric rename(F); 425306c3fb27SDimitry Andric NewFn = Intrinsic::getDeclaration(F->getParent(), IID); 425406c3fb27SDimitry Andric SmallVector<Value *, 2> Args; 425506c3fb27SDimitry Andric for (size_t I = 0; I < NewFn->arg_size(); ++I) { 425606c3fb27SDimitry Andric Value *Arg = CI->getArgOperand(I); 425706c3fb27SDimitry Andric Type *OldType = Arg->getType(); 425806c3fb27SDimitry Andric Type *NewType = NewFn->getArg(I)->getType(); 425906c3fb27SDimitry Andric Args.push_back((OldType->isIntegerTy() && 426006c3fb27SDimitry Andric NewType->getScalarType()->isBFloatTy()) 426106c3fb27SDimitry Andric ? Builder.CreateBitCast(Arg, NewType) 426206c3fb27SDimitry Andric : Arg); 426306c3fb27SDimitry Andric } 426406c3fb27SDimitry Andric Rep = Builder.CreateCall(NewFn, Args); 426506c3fb27SDimitry Andric if (F->getReturnType()->isIntegerTy()) 426606c3fb27SDimitry Andric Rep = Builder.CreateBitCast(Rep, F->getReturnType()); 426706c3fb27SDimitry Andric } 426806c3fb27SDimitry Andric } 4269*0fca6ea1SDimitry Andric } else if (IsX86) { 4270*0fca6ea1SDimitry Andric Rep = upgradeX86IntrinsicCall(Name, CI, F, Builder); 42710eae32dcSDimitry Andric } else if (IsARM) { 42727a6dacacSDimitry Andric Rep = upgradeARMIntrinsicCall(Name, CI, F, Builder); 427306c3fb27SDimitry Andric } else if (IsAMDGCN) { 42747a6dacacSDimitry Andric Rep = upgradeAMDGCNIntrinsicCall(Name, CI, F, Builder); 4275*0fca6ea1SDimitry Andric } else if (IsDbg) { 4276*0fca6ea1SDimitry Andric // We might have decided we don't want the new format after all between 4277*0fca6ea1SDimitry Andric // first requesting the upgrade and now; skip the conversion if that is 4278*0fca6ea1SDimitry Andric // the case, and check here to see if the intrinsic needs to be upgraded 4279*0fca6ea1SDimitry Andric // normally. 4280*0fca6ea1SDimitry Andric if (!CI->getModule()->IsNewDbgInfoFormat) { 4281*0fca6ea1SDimitry Andric bool NeedsUpgrade = 4282*0fca6ea1SDimitry Andric upgradeIntrinsicFunction1(CI->getCalledFunction(), NewFn, false); 4283*0fca6ea1SDimitry Andric if (!NeedsUpgrade) 4284*0fca6ea1SDimitry Andric return; 4285*0fca6ea1SDimitry Andric FallthroughToDefaultUpgrade = true; 4286*0fca6ea1SDimitry Andric } else { 4287*0fca6ea1SDimitry Andric upgradeDbgIntrinsicToDbgRecord(Name, CI); 4288*0fca6ea1SDimitry Andric } 42890b57cec5SDimitry Andric } else { 429081ad6265SDimitry Andric llvm_unreachable("Unknown function for CallBase upgrade."); 42910b57cec5SDimitry Andric } 42920b57cec5SDimitry Andric 4293*0fca6ea1SDimitry Andric if (!FallthroughToDefaultUpgrade) { 42940b57cec5SDimitry Andric if (Rep) 42950b57cec5SDimitry Andric CI->replaceAllUsesWith(Rep); 42960b57cec5SDimitry Andric CI->eraseFromParent(); 42970b57cec5SDimitry Andric return; 42980b57cec5SDimitry Andric } 4299*0fca6ea1SDimitry Andric } 43000b57cec5SDimitry Andric 430181ad6265SDimitry Andric const auto &DefaultCase = [&]() -> void { 430281ad6265SDimitry Andric if (CI->getFunctionType() == NewFn->getFunctionType()) { 430381ad6265SDimitry Andric // Handle generic mangling change. 43040b57cec5SDimitry Andric assert( 43050b57cec5SDimitry Andric (CI->getCalledFunction()->getName() != NewFn->getName()) && 430681ad6265SDimitry Andric "Unknown function for CallBase upgrade and isn't just a name change"); 43070b57cec5SDimitry Andric CI->setCalledFunction(NewFn); 430881ad6265SDimitry Andric return; 430981ad6265SDimitry Andric } 431081ad6265SDimitry Andric 431181ad6265SDimitry Andric // This must be an upgrade from a named to a literal struct. 4312bdd1243dSDimitry Andric if (auto *OldST = dyn_cast<StructType>(CI->getType())) { 4313bdd1243dSDimitry Andric assert(OldST != NewFn->getReturnType() && 4314bdd1243dSDimitry Andric "Return type must have changed"); 431581ad6265SDimitry Andric assert(OldST->getNumElements() == 431681ad6265SDimitry Andric cast<StructType>(NewFn->getReturnType())->getNumElements() && 431781ad6265SDimitry Andric "Must have same number of elements"); 431881ad6265SDimitry Andric 431981ad6265SDimitry Andric SmallVector<Value *> Args(CI->args()); 432081ad6265SDimitry Andric Value *NewCI = Builder.CreateCall(NewFn, Args); 432181ad6265SDimitry Andric Value *Res = PoisonValue::get(OldST); 432281ad6265SDimitry Andric for (unsigned Idx = 0; Idx < OldST->getNumElements(); ++Idx) { 432381ad6265SDimitry Andric Value *Elem = Builder.CreateExtractValue(NewCI, Idx); 432481ad6265SDimitry Andric Res = Builder.CreateInsertValue(Res, Elem, Idx); 432581ad6265SDimitry Andric } 432681ad6265SDimitry Andric CI->replaceAllUsesWith(Res); 432781ad6265SDimitry Andric CI->eraseFromParent(); 432881ad6265SDimitry Andric return; 4329bdd1243dSDimitry Andric } 4330bdd1243dSDimitry Andric 4331bdd1243dSDimitry Andric // We're probably about to produce something invalid. Let the verifier catch 4332bdd1243dSDimitry Andric // it instead of dying here. 4333bdd1243dSDimitry Andric CI->setCalledOperand( 4334bdd1243dSDimitry Andric ConstantExpr::getPointerCast(NewFn, CI->getCalledOperand()->getType())); 4335bdd1243dSDimitry Andric return; 43360b57cec5SDimitry Andric }; 43370b57cec5SDimitry Andric CallInst *NewCall = nullptr; 43380b57cec5SDimitry Andric switch (NewFn->getIntrinsicID()) { 43390b57cec5SDimitry Andric default: { 43400b57cec5SDimitry Andric DefaultCase(); 43410b57cec5SDimitry Andric return; 43420b57cec5SDimitry Andric } 43430b57cec5SDimitry Andric case Intrinsic::arm_neon_vst1: 43440b57cec5SDimitry Andric case Intrinsic::arm_neon_vst2: 43450b57cec5SDimitry Andric case Intrinsic::arm_neon_vst3: 43460b57cec5SDimitry Andric case Intrinsic::arm_neon_vst4: 43470b57cec5SDimitry Andric case Intrinsic::arm_neon_vst2lane: 43480b57cec5SDimitry Andric case Intrinsic::arm_neon_vst3lane: 43490b57cec5SDimitry Andric case Intrinsic::arm_neon_vst4lane: { 4350349cc55cSDimitry Andric SmallVector<Value *, 4> Args(CI->args()); 43510b57cec5SDimitry Andric NewCall = Builder.CreateCall(NewFn, Args); 43520b57cec5SDimitry Andric break; 43530b57cec5SDimitry Andric } 4354bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_bfmlalb_lane_v2: 4355bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_bfmlalt_lane_v2: 4356bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_bfdot_lane_v2: { 4357bdd1243dSDimitry Andric LLVMContext &Ctx = F->getParent()->getContext(); 4358bdd1243dSDimitry Andric SmallVector<Value *, 4> Args(CI->args()); 4359bdd1243dSDimitry Andric Args[3] = ConstantInt::get(Type::getInt32Ty(Ctx), 4360bdd1243dSDimitry Andric cast<ConstantInt>(Args[3])->getZExtValue()); 4361bdd1243dSDimitry Andric NewCall = Builder.CreateCall(NewFn, Args); 4362bdd1243dSDimitry Andric break; 4363bdd1243dSDimitry Andric } 4364bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_ld3_sret: 4365bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_ld4_sret: 4366bdd1243dSDimitry Andric case Intrinsic::aarch64_sve_ld2_sret: { 4367bdd1243dSDimitry Andric StringRef Name = F->getName(); 4368bdd1243dSDimitry Andric Name = Name.substr(5); 4369bdd1243dSDimitry Andric unsigned N = StringSwitch<unsigned>(Name) 4370bdd1243dSDimitry Andric .StartsWith("aarch64.sve.ld2", 2) 4371bdd1243dSDimitry Andric .StartsWith("aarch64.sve.ld3", 3) 4372bdd1243dSDimitry Andric .StartsWith("aarch64.sve.ld4", 4) 4373bdd1243dSDimitry Andric .Default(0); 4374*0fca6ea1SDimitry Andric auto *RetTy = cast<ScalableVectorType>(F->getReturnType()); 4375bdd1243dSDimitry Andric unsigned MinElts = RetTy->getMinNumElements() / N; 4376bdd1243dSDimitry Andric SmallVector<Value *, 2> Args(CI->args()); 4377bdd1243dSDimitry Andric Value *NewLdCall = Builder.CreateCall(NewFn, Args); 4378bdd1243dSDimitry Andric Value *Ret = llvm::PoisonValue::get(RetTy); 4379bdd1243dSDimitry Andric for (unsigned I = 0; I < N; I++) { 4380bdd1243dSDimitry Andric Value *Idx = ConstantInt::get(Type::getInt64Ty(C), I * MinElts); 4381bdd1243dSDimitry Andric Value *SRet = Builder.CreateExtractValue(NewLdCall, I); 4382bdd1243dSDimitry Andric Ret = Builder.CreateInsertVector(RetTy, Ret, SRet, Idx); 4383bdd1243dSDimitry Andric } 4384bdd1243dSDimitry Andric NewCall = dyn_cast<CallInst>(Ret); 4385bdd1243dSDimitry Andric break; 4386bdd1243dSDimitry Andric } 4387bdd1243dSDimitry Andric 43885f757f3fSDimitry Andric case Intrinsic::coro_end: { 43895f757f3fSDimitry Andric SmallVector<Value *, 3> Args(CI->args()); 43905f757f3fSDimitry Andric Args.push_back(ConstantTokenNone::get(CI->getContext())); 43915f757f3fSDimitry Andric NewCall = Builder.CreateCall(NewFn, Args); 43925f757f3fSDimitry Andric break; 43935f757f3fSDimitry Andric } 43945f757f3fSDimitry Andric 4395bdd1243dSDimitry Andric case Intrinsic::vector_extract: { 4396bdd1243dSDimitry Andric StringRef Name = F->getName(); 4397bdd1243dSDimitry Andric Name = Name.substr(5); // Strip llvm 43985f757f3fSDimitry Andric if (!Name.starts_with("aarch64.sve.tuple.get")) { 4399bdd1243dSDimitry Andric DefaultCase(); 4400bdd1243dSDimitry Andric return; 4401bdd1243dSDimitry Andric } 4402*0fca6ea1SDimitry Andric auto *RetTy = cast<ScalableVectorType>(F->getReturnType()); 4403bdd1243dSDimitry Andric unsigned MinElts = RetTy->getMinNumElements(); 4404bdd1243dSDimitry Andric unsigned I = cast<ConstantInt>(CI->getArgOperand(1))->getZExtValue(); 4405bdd1243dSDimitry Andric Value *NewIdx = ConstantInt::get(Type::getInt64Ty(C), I * MinElts); 4406bdd1243dSDimitry Andric NewCall = Builder.CreateCall(NewFn, {CI->getArgOperand(0), NewIdx}); 4407bdd1243dSDimitry Andric break; 4408bdd1243dSDimitry Andric } 4409bdd1243dSDimitry Andric 4410bdd1243dSDimitry Andric case Intrinsic::vector_insert: { 4411bdd1243dSDimitry Andric StringRef Name = F->getName(); 4412bdd1243dSDimitry Andric Name = Name.substr(5); 44135f757f3fSDimitry Andric if (!Name.starts_with("aarch64.sve.tuple")) { 4414bdd1243dSDimitry Andric DefaultCase(); 4415bdd1243dSDimitry Andric return; 4416bdd1243dSDimitry Andric } 44175f757f3fSDimitry Andric if (Name.starts_with("aarch64.sve.tuple.set")) { 4418*0fca6ea1SDimitry Andric unsigned I = cast<ConstantInt>(CI->getArgOperand(1))->getZExtValue(); 4419*0fca6ea1SDimitry Andric auto *Ty = cast<ScalableVectorType>(CI->getArgOperand(2)->getType()); 4420bdd1243dSDimitry Andric Value *NewIdx = 4421bdd1243dSDimitry Andric ConstantInt::get(Type::getInt64Ty(C), I * Ty->getMinNumElements()); 4422bdd1243dSDimitry Andric NewCall = Builder.CreateCall( 4423bdd1243dSDimitry Andric NewFn, {CI->getArgOperand(0), CI->getArgOperand(2), NewIdx}); 4424bdd1243dSDimitry Andric break; 4425bdd1243dSDimitry Andric } 44265f757f3fSDimitry Andric if (Name.starts_with("aarch64.sve.tuple.create")) { 4427bdd1243dSDimitry Andric unsigned N = StringSwitch<unsigned>(Name) 4428bdd1243dSDimitry Andric .StartsWith("aarch64.sve.tuple.create2", 2) 4429bdd1243dSDimitry Andric .StartsWith("aarch64.sve.tuple.create3", 3) 4430bdd1243dSDimitry Andric .StartsWith("aarch64.sve.tuple.create4", 4) 4431bdd1243dSDimitry Andric .Default(0); 4432bdd1243dSDimitry Andric assert(N > 1 && "Create is expected to be between 2-4"); 4433*0fca6ea1SDimitry Andric auto *RetTy = cast<ScalableVectorType>(F->getReturnType()); 4434bdd1243dSDimitry Andric Value *Ret = llvm::PoisonValue::get(RetTy); 4435bdd1243dSDimitry Andric unsigned MinElts = RetTy->getMinNumElements() / N; 4436bdd1243dSDimitry Andric for (unsigned I = 0; I < N; I++) { 4437bdd1243dSDimitry Andric Value *Idx = ConstantInt::get(Type::getInt64Ty(C), I * MinElts); 4438bdd1243dSDimitry Andric Value *V = CI->getArgOperand(I); 4439bdd1243dSDimitry Andric Ret = Builder.CreateInsertVector(RetTy, Ret, V, Idx); 4440bdd1243dSDimitry Andric } 4441bdd1243dSDimitry Andric NewCall = dyn_cast<CallInst>(Ret); 4442bdd1243dSDimitry Andric } 4443bdd1243dSDimitry Andric break; 4444bdd1243dSDimitry Andric } 44450b57cec5SDimitry Andric 4446e8d8bef9SDimitry Andric case Intrinsic::arm_neon_bfdot: 4447e8d8bef9SDimitry Andric case Intrinsic::arm_neon_bfmmla: 4448e8d8bef9SDimitry Andric case Intrinsic::arm_neon_bfmlalb: 4449e8d8bef9SDimitry Andric case Intrinsic::arm_neon_bfmlalt: 4450e8d8bef9SDimitry Andric case Intrinsic::aarch64_neon_bfdot: 4451e8d8bef9SDimitry Andric case Intrinsic::aarch64_neon_bfmmla: 4452e8d8bef9SDimitry Andric case Intrinsic::aarch64_neon_bfmlalb: 4453e8d8bef9SDimitry Andric case Intrinsic::aarch64_neon_bfmlalt: { 4454e8d8bef9SDimitry Andric SmallVector<Value *, 3> Args; 4455349cc55cSDimitry Andric assert(CI->arg_size() == 3 && 4456e8d8bef9SDimitry Andric "Mismatch between function args and call args"); 4457e8d8bef9SDimitry Andric size_t OperandWidth = 4458e8d8bef9SDimitry Andric CI->getArgOperand(1)->getType()->getPrimitiveSizeInBits(); 4459e8d8bef9SDimitry Andric assert((OperandWidth == 64 || OperandWidth == 128) && 4460e8d8bef9SDimitry Andric "Unexpected operand width"); 4461e8d8bef9SDimitry Andric Type *NewTy = FixedVectorType::get(Type::getBFloatTy(C), OperandWidth / 16); 4462349cc55cSDimitry Andric auto Iter = CI->args().begin(); 4463e8d8bef9SDimitry Andric Args.push_back(*Iter++); 4464e8d8bef9SDimitry Andric Args.push_back(Builder.CreateBitCast(*Iter++, NewTy)); 4465e8d8bef9SDimitry Andric Args.push_back(Builder.CreateBitCast(*Iter++, NewTy)); 4466e8d8bef9SDimitry Andric NewCall = Builder.CreateCall(NewFn, Args); 4467e8d8bef9SDimitry Andric break; 4468e8d8bef9SDimitry Andric } 4469e8d8bef9SDimitry Andric 44700b57cec5SDimitry Andric case Intrinsic::bitreverse: 44710b57cec5SDimitry Andric NewCall = Builder.CreateCall(NewFn, {CI->getArgOperand(0)}); 44720b57cec5SDimitry Andric break; 44730b57cec5SDimitry Andric 44740b57cec5SDimitry Andric case Intrinsic::ctlz: 44750b57cec5SDimitry Andric case Intrinsic::cttz: 4476349cc55cSDimitry Andric assert(CI->arg_size() == 1 && 44770b57cec5SDimitry Andric "Mismatch between function args and call args"); 44780b57cec5SDimitry Andric NewCall = 44790b57cec5SDimitry Andric Builder.CreateCall(NewFn, {CI->getArgOperand(0), Builder.getFalse()}); 44800b57cec5SDimitry Andric break; 44810b57cec5SDimitry Andric 44820b57cec5SDimitry Andric case Intrinsic::objectsize: { 4483349cc55cSDimitry Andric Value *NullIsUnknownSize = 4484349cc55cSDimitry Andric CI->arg_size() == 2 ? Builder.getFalse() : CI->getArgOperand(2); 44850b57cec5SDimitry Andric Value *Dynamic = 4486349cc55cSDimitry Andric CI->arg_size() < 4 ? Builder.getFalse() : CI->getArgOperand(3); 44870b57cec5SDimitry Andric NewCall = Builder.CreateCall( 44880b57cec5SDimitry Andric NewFn, {CI->getArgOperand(0), CI->getArgOperand(1), NullIsUnknownSize, Dynamic}); 44890b57cec5SDimitry Andric break; 44900b57cec5SDimitry Andric } 44910b57cec5SDimitry Andric 44920b57cec5SDimitry Andric case Intrinsic::ctpop: 44930b57cec5SDimitry Andric NewCall = Builder.CreateCall(NewFn, {CI->getArgOperand(0)}); 44940b57cec5SDimitry Andric break; 44950b57cec5SDimitry Andric 44960b57cec5SDimitry Andric case Intrinsic::convert_from_fp16: 44970b57cec5SDimitry Andric NewCall = Builder.CreateCall(NewFn, {CI->getArgOperand(0)}); 44980b57cec5SDimitry Andric break; 44990b57cec5SDimitry Andric 450006c3fb27SDimitry Andric case Intrinsic::dbg_value: { 450106c3fb27SDimitry Andric StringRef Name = F->getName(); 450206c3fb27SDimitry Andric Name = Name.substr(5); // Strip llvm. 450306c3fb27SDimitry Andric // Upgrade `dbg.addr` to `dbg.value` with `DW_OP_deref`. 45045f757f3fSDimitry Andric if (Name.starts_with("dbg.addr")) { 450506c3fb27SDimitry Andric DIExpression *Expr = cast<DIExpression>( 450606c3fb27SDimitry Andric cast<MetadataAsValue>(CI->getArgOperand(2))->getMetadata()); 450706c3fb27SDimitry Andric Expr = DIExpression::append(Expr, dwarf::DW_OP_deref); 450806c3fb27SDimitry Andric NewCall = 450906c3fb27SDimitry Andric Builder.CreateCall(NewFn, {CI->getArgOperand(0), CI->getArgOperand(1), 451006c3fb27SDimitry Andric MetadataAsValue::get(C, Expr)}); 451106c3fb27SDimitry Andric break; 451206c3fb27SDimitry Andric } 451306c3fb27SDimitry Andric 45140b57cec5SDimitry Andric // Upgrade from the old version that had an extra offset argument. 4515349cc55cSDimitry Andric assert(CI->arg_size() == 4); 45160b57cec5SDimitry Andric // Drop nonzero offsets instead of attempting to upgrade them. 45170b57cec5SDimitry Andric if (auto *Offset = dyn_cast_or_null<Constant>(CI->getArgOperand(1))) 45180b57cec5SDimitry Andric if (Offset->isZeroValue()) { 45190b57cec5SDimitry Andric NewCall = Builder.CreateCall( 45200b57cec5SDimitry Andric NewFn, 45210b57cec5SDimitry Andric {CI->getArgOperand(0), CI->getArgOperand(2), CI->getArgOperand(3)}); 45220b57cec5SDimitry Andric break; 45230b57cec5SDimitry Andric } 45240b57cec5SDimitry Andric CI->eraseFromParent(); 45250b57cec5SDimitry Andric return; 452606c3fb27SDimitry Andric } 45270b57cec5SDimitry Andric 4528d409305fSDimitry Andric case Intrinsic::ptr_annotation: 4529d409305fSDimitry Andric // Upgrade from versions that lacked the annotation attribute argument. 453081ad6265SDimitry Andric if (CI->arg_size() != 4) { 453181ad6265SDimitry Andric DefaultCase(); 453281ad6265SDimitry Andric return; 453381ad6265SDimitry Andric } 453481ad6265SDimitry Andric 4535d409305fSDimitry Andric // Create a new call with an added null annotation attribute argument. 45365f757f3fSDimitry Andric NewCall = 45375f757f3fSDimitry Andric Builder.CreateCall(NewFn, {CI->getArgOperand(0), CI->getArgOperand(1), 45385f757f3fSDimitry Andric CI->getArgOperand(2), CI->getArgOperand(3), 45395f757f3fSDimitry Andric Constant::getNullValue(Builder.getPtrTy())}); 4540d409305fSDimitry Andric NewCall->takeName(CI); 4541d409305fSDimitry Andric CI->replaceAllUsesWith(NewCall); 4542d409305fSDimitry Andric CI->eraseFromParent(); 4543d409305fSDimitry Andric return; 4544d409305fSDimitry Andric 4545d409305fSDimitry Andric case Intrinsic::var_annotation: 4546d409305fSDimitry Andric // Upgrade from versions that lacked the annotation attribute argument. 4547bdd1243dSDimitry Andric if (CI->arg_size() != 4) { 4548bdd1243dSDimitry Andric DefaultCase(); 4549bdd1243dSDimitry Andric return; 4550bdd1243dSDimitry Andric } 4551d409305fSDimitry Andric // Create a new call with an added null annotation attribute argument. 45525f757f3fSDimitry Andric NewCall = 45535f757f3fSDimitry Andric Builder.CreateCall(NewFn, {CI->getArgOperand(0), CI->getArgOperand(1), 45545f757f3fSDimitry Andric CI->getArgOperand(2), CI->getArgOperand(3), 45555f757f3fSDimitry Andric Constant::getNullValue(Builder.getPtrTy())}); 4556bdd1243dSDimitry Andric NewCall->takeName(CI); 4557bdd1243dSDimitry Andric CI->replaceAllUsesWith(NewCall); 4558d409305fSDimitry Andric CI->eraseFromParent(); 4559d409305fSDimitry Andric return; 4560d409305fSDimitry Andric 456106c3fb27SDimitry Andric case Intrinsic::riscv_aes32dsi: 456206c3fb27SDimitry Andric case Intrinsic::riscv_aes32dsmi: 456306c3fb27SDimitry Andric case Intrinsic::riscv_aes32esi: 456406c3fb27SDimitry Andric case Intrinsic::riscv_aes32esmi: 456506c3fb27SDimitry Andric case Intrinsic::riscv_sm4ks: 456606c3fb27SDimitry Andric case Intrinsic::riscv_sm4ed: { 456706c3fb27SDimitry Andric // The last argument to these intrinsics used to be i8 and changed to i32. 456806c3fb27SDimitry Andric // The type overload for sm4ks and sm4ed was removed. 456906c3fb27SDimitry Andric Value *Arg2 = CI->getArgOperand(2); 457006c3fb27SDimitry Andric if (Arg2->getType()->isIntegerTy(32) && !CI->getType()->isIntegerTy(64)) 457106c3fb27SDimitry Andric return; 457206c3fb27SDimitry Andric 457306c3fb27SDimitry Andric Value *Arg0 = CI->getArgOperand(0); 457406c3fb27SDimitry Andric Value *Arg1 = CI->getArgOperand(1); 457506c3fb27SDimitry Andric if (CI->getType()->isIntegerTy(64)) { 457606c3fb27SDimitry Andric Arg0 = Builder.CreateTrunc(Arg0, Builder.getInt32Ty()); 457706c3fb27SDimitry Andric Arg1 = Builder.CreateTrunc(Arg1, Builder.getInt32Ty()); 457806c3fb27SDimitry Andric } 457906c3fb27SDimitry Andric 458006c3fb27SDimitry Andric Arg2 = ConstantInt::get(Type::getInt32Ty(C), 458106c3fb27SDimitry Andric cast<ConstantInt>(Arg2)->getZExtValue()); 458206c3fb27SDimitry Andric 458306c3fb27SDimitry Andric NewCall = Builder.CreateCall(NewFn, {Arg0, Arg1, Arg2}); 458406c3fb27SDimitry Andric Value *Res = NewCall; 458506c3fb27SDimitry Andric if (Res->getType() != CI->getType()) 458606c3fb27SDimitry Andric Res = Builder.CreateIntCast(NewCall, CI->getType(), /*isSigned*/ true); 458706c3fb27SDimitry Andric NewCall->takeName(CI); 458806c3fb27SDimitry Andric CI->replaceAllUsesWith(Res); 458906c3fb27SDimitry Andric CI->eraseFromParent(); 459006c3fb27SDimitry Andric return; 459106c3fb27SDimitry Andric } 459206c3fb27SDimitry Andric case Intrinsic::riscv_sha256sig0: 459306c3fb27SDimitry Andric case Intrinsic::riscv_sha256sig1: 459406c3fb27SDimitry Andric case Intrinsic::riscv_sha256sum0: 459506c3fb27SDimitry Andric case Intrinsic::riscv_sha256sum1: 459606c3fb27SDimitry Andric case Intrinsic::riscv_sm3p0: 459706c3fb27SDimitry Andric case Intrinsic::riscv_sm3p1: { 459806c3fb27SDimitry Andric // The last argument to these intrinsics used to be i8 and changed to i32. 459906c3fb27SDimitry Andric // The type overload for sm4ks and sm4ed was removed. 460006c3fb27SDimitry Andric if (!CI->getType()->isIntegerTy(64)) 460106c3fb27SDimitry Andric return; 460206c3fb27SDimitry Andric 460306c3fb27SDimitry Andric Value *Arg = 460406c3fb27SDimitry Andric Builder.CreateTrunc(CI->getArgOperand(0), Builder.getInt32Ty()); 460506c3fb27SDimitry Andric 460606c3fb27SDimitry Andric NewCall = Builder.CreateCall(NewFn, Arg); 460706c3fb27SDimitry Andric Value *Res = 460806c3fb27SDimitry Andric Builder.CreateIntCast(NewCall, CI->getType(), /*isSigned*/ true); 460906c3fb27SDimitry Andric NewCall->takeName(CI); 461006c3fb27SDimitry Andric CI->replaceAllUsesWith(Res); 461106c3fb27SDimitry Andric CI->eraseFromParent(); 461206c3fb27SDimitry Andric return; 461306c3fb27SDimitry Andric } 461406c3fb27SDimitry Andric 46150b57cec5SDimitry Andric case Intrinsic::x86_xop_vfrcz_ss: 46160b57cec5SDimitry Andric case Intrinsic::x86_xop_vfrcz_sd: 46170b57cec5SDimitry Andric NewCall = Builder.CreateCall(NewFn, {CI->getArgOperand(1)}); 46180b57cec5SDimitry Andric break; 46190b57cec5SDimitry Andric 46200b57cec5SDimitry Andric case Intrinsic::x86_xop_vpermil2pd: 46210b57cec5SDimitry Andric case Intrinsic::x86_xop_vpermil2ps: 46220b57cec5SDimitry Andric case Intrinsic::x86_xop_vpermil2pd_256: 46230b57cec5SDimitry Andric case Intrinsic::x86_xop_vpermil2ps_256: { 4624349cc55cSDimitry Andric SmallVector<Value *, 4> Args(CI->args()); 46250b57cec5SDimitry Andric VectorType *FltIdxTy = cast<VectorType>(Args[2]->getType()); 46260b57cec5SDimitry Andric VectorType *IntIdxTy = VectorType::getInteger(FltIdxTy); 46270b57cec5SDimitry Andric Args[2] = Builder.CreateBitCast(Args[2], IntIdxTy); 46280b57cec5SDimitry Andric NewCall = Builder.CreateCall(NewFn, Args); 46290b57cec5SDimitry Andric break; 46300b57cec5SDimitry Andric } 46310b57cec5SDimitry Andric 46320b57cec5SDimitry Andric case Intrinsic::x86_sse41_ptestc: 46330b57cec5SDimitry Andric case Intrinsic::x86_sse41_ptestz: 46340b57cec5SDimitry Andric case Intrinsic::x86_sse41_ptestnzc: { 46350b57cec5SDimitry Andric // The arguments for these intrinsics used to be v4f32, and changed 46360b57cec5SDimitry Andric // to v2i64. This is purely a nop, since those are bitwise intrinsics. 46370b57cec5SDimitry Andric // So, the only thing required is a bitcast for both arguments. 46380b57cec5SDimitry Andric // First, check the arguments have the old type. 46390b57cec5SDimitry Andric Value *Arg0 = CI->getArgOperand(0); 46405ffd83dbSDimitry Andric if (Arg0->getType() != FixedVectorType::get(Type::getFloatTy(C), 4)) 46410b57cec5SDimitry Andric return; 46420b57cec5SDimitry Andric 46430b57cec5SDimitry Andric // Old intrinsic, add bitcasts 46440b57cec5SDimitry Andric Value *Arg1 = CI->getArgOperand(1); 46450b57cec5SDimitry Andric 46465ffd83dbSDimitry Andric auto *NewVecTy = FixedVectorType::get(Type::getInt64Ty(C), 2); 46470b57cec5SDimitry Andric 46480b57cec5SDimitry Andric Value *BC0 = Builder.CreateBitCast(Arg0, NewVecTy, "cast"); 46490b57cec5SDimitry Andric Value *BC1 = Builder.CreateBitCast(Arg1, NewVecTy, "cast"); 46500b57cec5SDimitry Andric 46510b57cec5SDimitry Andric NewCall = Builder.CreateCall(NewFn, {BC0, BC1}); 46520b57cec5SDimitry Andric break; 46530b57cec5SDimitry Andric } 46540b57cec5SDimitry Andric 46550b57cec5SDimitry Andric case Intrinsic::x86_rdtscp: { 46560b57cec5SDimitry Andric // This used to take 1 arguments. If we have no arguments, it is already 46570b57cec5SDimitry Andric // upgraded. 46580b57cec5SDimitry Andric if (CI->getNumOperands() == 0) 46590b57cec5SDimitry Andric return; 46600b57cec5SDimitry Andric 46610b57cec5SDimitry Andric NewCall = Builder.CreateCall(NewFn); 46620b57cec5SDimitry Andric // Extract the second result and store it. 46630b57cec5SDimitry Andric Value *Data = Builder.CreateExtractValue(NewCall, 1); 46640b57cec5SDimitry Andric // Cast the pointer to the right type. 46650b57cec5SDimitry Andric Value *Ptr = Builder.CreateBitCast(CI->getArgOperand(0), 46660b57cec5SDimitry Andric llvm::PointerType::getUnqual(Data->getType())); 46675ffd83dbSDimitry Andric Builder.CreateAlignedStore(Data, Ptr, Align(1)); 46680b57cec5SDimitry Andric // Replace the original call result with the first result of the new call. 46690b57cec5SDimitry Andric Value *TSC = Builder.CreateExtractValue(NewCall, 0); 46700b57cec5SDimitry Andric 4671e8d8bef9SDimitry Andric NewCall->takeName(CI); 46720b57cec5SDimitry Andric CI->replaceAllUsesWith(TSC); 46730b57cec5SDimitry Andric CI->eraseFromParent(); 46740b57cec5SDimitry Andric return; 46750b57cec5SDimitry Andric } 46760b57cec5SDimitry Andric 46770b57cec5SDimitry Andric case Intrinsic::x86_sse41_insertps: 46780b57cec5SDimitry Andric case Intrinsic::x86_sse41_dppd: 46790b57cec5SDimitry Andric case Intrinsic::x86_sse41_dpps: 46800b57cec5SDimitry Andric case Intrinsic::x86_sse41_mpsadbw: 46810b57cec5SDimitry Andric case Intrinsic::x86_avx_dp_ps_256: 46820b57cec5SDimitry Andric case Intrinsic::x86_avx2_mpsadbw: { 46830b57cec5SDimitry Andric // Need to truncate the last argument from i32 to i8 -- this argument models 46840b57cec5SDimitry Andric // an inherently 8-bit immediate operand to these x86 instructions. 4685349cc55cSDimitry Andric SmallVector<Value *, 4> Args(CI->args()); 46860b57cec5SDimitry Andric 46870b57cec5SDimitry Andric // Replace the last argument with a trunc. 46880b57cec5SDimitry Andric Args.back() = Builder.CreateTrunc(Args.back(), Type::getInt8Ty(C), "trunc"); 46890b57cec5SDimitry Andric NewCall = Builder.CreateCall(NewFn, Args); 46900b57cec5SDimitry Andric break; 46910b57cec5SDimitry Andric } 46920b57cec5SDimitry Andric 4693e8d8bef9SDimitry Andric case Intrinsic::x86_avx512_mask_cmp_pd_128: 4694e8d8bef9SDimitry Andric case Intrinsic::x86_avx512_mask_cmp_pd_256: 4695e8d8bef9SDimitry Andric case Intrinsic::x86_avx512_mask_cmp_pd_512: 4696e8d8bef9SDimitry Andric case Intrinsic::x86_avx512_mask_cmp_ps_128: 4697e8d8bef9SDimitry Andric case Intrinsic::x86_avx512_mask_cmp_ps_256: 4698e8d8bef9SDimitry Andric case Intrinsic::x86_avx512_mask_cmp_ps_512: { 4699349cc55cSDimitry Andric SmallVector<Value *, 4> Args(CI->args()); 4700e8d8bef9SDimitry Andric unsigned NumElts = 4701e8d8bef9SDimitry Andric cast<FixedVectorType>(Args[0]->getType())->getNumElements(); 4702e8d8bef9SDimitry Andric Args[3] = getX86MaskVec(Builder, Args[3], NumElts); 4703e8d8bef9SDimitry Andric 4704e8d8bef9SDimitry Andric NewCall = Builder.CreateCall(NewFn, Args); 47057a6dacacSDimitry Andric Value *Res = applyX86MaskOn1BitsVec(Builder, NewCall, nullptr); 4706e8d8bef9SDimitry Andric 4707e8d8bef9SDimitry Andric NewCall->takeName(CI); 4708e8d8bef9SDimitry Andric CI->replaceAllUsesWith(Res); 4709e8d8bef9SDimitry Andric CI->eraseFromParent(); 4710e8d8bef9SDimitry Andric return; 4711e8d8bef9SDimitry Andric } 4712e8d8bef9SDimitry Andric 4713bdd1243dSDimitry Andric case Intrinsic::x86_avx512bf16_cvtne2ps2bf16_128: 4714bdd1243dSDimitry Andric case Intrinsic::x86_avx512bf16_cvtne2ps2bf16_256: 4715bdd1243dSDimitry Andric case Intrinsic::x86_avx512bf16_cvtne2ps2bf16_512: 4716bdd1243dSDimitry Andric case Intrinsic::x86_avx512bf16_mask_cvtneps2bf16_128: 4717bdd1243dSDimitry Andric case Intrinsic::x86_avx512bf16_cvtneps2bf16_256: 4718bdd1243dSDimitry Andric case Intrinsic::x86_avx512bf16_cvtneps2bf16_512: { 4719bdd1243dSDimitry Andric SmallVector<Value *, 4> Args(CI->args()); 4720bdd1243dSDimitry Andric unsigned NumElts = cast<FixedVectorType>(CI->getType())->getNumElements(); 4721bdd1243dSDimitry Andric if (NewFn->getIntrinsicID() == 4722bdd1243dSDimitry Andric Intrinsic::x86_avx512bf16_mask_cvtneps2bf16_128) 4723bdd1243dSDimitry Andric Args[1] = Builder.CreateBitCast( 4724bdd1243dSDimitry Andric Args[1], FixedVectorType::get(Builder.getBFloatTy(), NumElts)); 4725bdd1243dSDimitry Andric 4726bdd1243dSDimitry Andric NewCall = Builder.CreateCall(NewFn, Args); 4727bdd1243dSDimitry Andric Value *Res = Builder.CreateBitCast( 4728bdd1243dSDimitry Andric NewCall, FixedVectorType::get(Builder.getInt16Ty(), NumElts)); 4729bdd1243dSDimitry Andric 4730bdd1243dSDimitry Andric NewCall->takeName(CI); 4731bdd1243dSDimitry Andric CI->replaceAllUsesWith(Res); 4732bdd1243dSDimitry Andric CI->eraseFromParent(); 4733bdd1243dSDimitry Andric return; 4734bdd1243dSDimitry Andric } 4735bdd1243dSDimitry Andric case Intrinsic::x86_avx512bf16_dpbf16ps_128: 4736bdd1243dSDimitry Andric case Intrinsic::x86_avx512bf16_dpbf16ps_256: 4737bdd1243dSDimitry Andric case Intrinsic::x86_avx512bf16_dpbf16ps_512:{ 4738bdd1243dSDimitry Andric SmallVector<Value *, 4> Args(CI->args()); 4739bdd1243dSDimitry Andric unsigned NumElts = 4740bdd1243dSDimitry Andric cast<FixedVectorType>(CI->getType())->getNumElements() * 2; 4741bdd1243dSDimitry Andric Args[1] = Builder.CreateBitCast( 4742bdd1243dSDimitry Andric Args[1], FixedVectorType::get(Builder.getBFloatTy(), NumElts)); 4743bdd1243dSDimitry Andric Args[2] = Builder.CreateBitCast( 4744bdd1243dSDimitry Andric Args[2], FixedVectorType::get(Builder.getBFloatTy(), NumElts)); 4745bdd1243dSDimitry Andric 4746bdd1243dSDimitry Andric NewCall = Builder.CreateCall(NewFn, Args); 4747bdd1243dSDimitry Andric break; 4748bdd1243dSDimitry Andric } 4749bdd1243dSDimitry Andric 47500b57cec5SDimitry Andric case Intrinsic::thread_pointer: { 47510b57cec5SDimitry Andric NewCall = Builder.CreateCall(NewFn, {}); 47520b57cec5SDimitry Andric break; 47530b57cec5SDimitry Andric } 47540b57cec5SDimitry Andric 47550b57cec5SDimitry Andric case Intrinsic::memcpy: 47560b57cec5SDimitry Andric case Intrinsic::memmove: 47570b57cec5SDimitry Andric case Intrinsic::memset: { 47580b57cec5SDimitry Andric // We have to make sure that the call signature is what we're expecting. 47590b57cec5SDimitry Andric // We only want to change the old signatures by removing the alignment arg: 47600b57cec5SDimitry Andric // @llvm.mem[cpy|move]...(i8*, i8*, i[32|i64], i32, i1) 47610b57cec5SDimitry Andric // -> @llvm.mem[cpy|move]...(i8*, i8*, i[32|i64], i1) 47620b57cec5SDimitry Andric // @llvm.memset...(i8*, i8, i[32|64], i32, i1) 47630b57cec5SDimitry Andric // -> @llvm.memset...(i8*, i8, i[32|64], i1) 47640b57cec5SDimitry Andric // Note: i8*'s in the above can be any pointer type 4765349cc55cSDimitry Andric if (CI->arg_size() != 5) { 47660b57cec5SDimitry Andric DefaultCase(); 47670b57cec5SDimitry Andric return; 47680b57cec5SDimitry Andric } 47690b57cec5SDimitry Andric // Remove alignment argument (3), and add alignment attributes to the 47700b57cec5SDimitry Andric // dest/src pointers. 47710b57cec5SDimitry Andric Value *Args[4] = {CI->getArgOperand(0), CI->getArgOperand(1), 47720b57cec5SDimitry Andric CI->getArgOperand(2), CI->getArgOperand(4)}; 47730b57cec5SDimitry Andric NewCall = Builder.CreateCall(NewFn, Args); 477481ad6265SDimitry Andric AttributeList OldAttrs = CI->getAttributes(); 477581ad6265SDimitry Andric AttributeList NewAttrs = AttributeList::get( 477681ad6265SDimitry Andric C, OldAttrs.getFnAttrs(), OldAttrs.getRetAttrs(), 477781ad6265SDimitry Andric {OldAttrs.getParamAttrs(0), OldAttrs.getParamAttrs(1), 477881ad6265SDimitry Andric OldAttrs.getParamAttrs(2), OldAttrs.getParamAttrs(4)}); 477981ad6265SDimitry Andric NewCall->setAttributes(NewAttrs); 47800b57cec5SDimitry Andric auto *MemCI = cast<MemIntrinsic>(NewCall); 47810b57cec5SDimitry Andric // All mem intrinsics support dest alignment. 47820b57cec5SDimitry Andric const ConstantInt *Align = cast<ConstantInt>(CI->getArgOperand(3)); 47835ffd83dbSDimitry Andric MemCI->setDestAlignment(Align->getMaybeAlignValue()); 47840b57cec5SDimitry Andric // Memcpy/Memmove also support source alignment. 47850b57cec5SDimitry Andric if (auto *MTI = dyn_cast<MemTransferInst>(MemCI)) 47865ffd83dbSDimitry Andric MTI->setSourceAlignment(Align->getMaybeAlignValue()); 47870b57cec5SDimitry Andric break; 47880b57cec5SDimitry Andric } 47890b57cec5SDimitry Andric } 47900b57cec5SDimitry Andric assert(NewCall && "Should have either set this variable or returned through " 47910b57cec5SDimitry Andric "the default case"); 4792e8d8bef9SDimitry Andric NewCall->takeName(CI); 47930b57cec5SDimitry Andric CI->replaceAllUsesWith(NewCall); 47940b57cec5SDimitry Andric CI->eraseFromParent(); 47950b57cec5SDimitry Andric } 47960b57cec5SDimitry Andric 47970b57cec5SDimitry Andric void llvm::UpgradeCallsToIntrinsic(Function *F) { 47980b57cec5SDimitry Andric assert(F && "Illegal attempt to upgrade a non-existent intrinsic."); 47990b57cec5SDimitry Andric 48000b57cec5SDimitry Andric // Check if this function should be upgraded and get the replacement function 48010b57cec5SDimitry Andric // if there is one. 48020b57cec5SDimitry Andric Function *NewFn; 48030b57cec5SDimitry Andric if (UpgradeIntrinsicFunction(F, NewFn)) { 48040b57cec5SDimitry Andric // Replace all users of the old function with the new function or new 48050b57cec5SDimitry Andric // instructions. This is not a range loop because the call is deleted. 4806e8d8bef9SDimitry Andric for (User *U : make_early_inc_range(F->users())) 480781ad6265SDimitry Andric if (CallBase *CB = dyn_cast<CallBase>(U)) 480881ad6265SDimitry Andric UpgradeIntrinsicCall(CB, NewFn); 48090b57cec5SDimitry Andric 48100b57cec5SDimitry Andric // Remove old function, no longer used, from the module. 48110b57cec5SDimitry Andric F->eraseFromParent(); 48120b57cec5SDimitry Andric } 48130b57cec5SDimitry Andric } 48140b57cec5SDimitry Andric 48150b57cec5SDimitry Andric MDNode *llvm::UpgradeTBAANode(MDNode &MD) { 481606c3fb27SDimitry Andric const unsigned NumOperands = MD.getNumOperands(); 481706c3fb27SDimitry Andric if (NumOperands == 0) 481806c3fb27SDimitry Andric return &MD; // Invalid, punt to a verifier error. 481906c3fb27SDimitry Andric 48200b57cec5SDimitry Andric // Check if the tag uses struct-path aware TBAA format. 482106c3fb27SDimitry Andric if (isa<MDNode>(MD.getOperand(0)) && NumOperands >= 3) 48220b57cec5SDimitry Andric return &MD; 48230b57cec5SDimitry Andric 48240b57cec5SDimitry Andric auto &Context = MD.getContext(); 482506c3fb27SDimitry Andric if (NumOperands == 3) { 48260b57cec5SDimitry Andric Metadata *Elts[] = {MD.getOperand(0), MD.getOperand(1)}; 48270b57cec5SDimitry Andric MDNode *ScalarType = MDNode::get(Context, Elts); 48280b57cec5SDimitry Andric // Create a MDNode <ScalarType, ScalarType, offset 0, const> 48290b57cec5SDimitry Andric Metadata *Elts2[] = {ScalarType, ScalarType, 48300b57cec5SDimitry Andric ConstantAsMetadata::get( 48310b57cec5SDimitry Andric Constant::getNullValue(Type::getInt64Ty(Context))), 48320b57cec5SDimitry Andric MD.getOperand(2)}; 48330b57cec5SDimitry Andric return MDNode::get(Context, Elts2); 48340b57cec5SDimitry Andric } 48350b57cec5SDimitry Andric // Create a MDNode <MD, MD, offset 0> 48360b57cec5SDimitry Andric Metadata *Elts[] = {&MD, &MD, ConstantAsMetadata::get(Constant::getNullValue( 48370b57cec5SDimitry Andric Type::getInt64Ty(Context)))}; 48380b57cec5SDimitry Andric return MDNode::get(Context, Elts); 48390b57cec5SDimitry Andric } 48400b57cec5SDimitry Andric 48410b57cec5SDimitry Andric Instruction *llvm::UpgradeBitCastInst(unsigned Opc, Value *V, Type *DestTy, 48420b57cec5SDimitry Andric Instruction *&Temp) { 48430b57cec5SDimitry Andric if (Opc != Instruction::BitCast) 48440b57cec5SDimitry Andric return nullptr; 48450b57cec5SDimitry Andric 48460b57cec5SDimitry Andric Temp = nullptr; 48470b57cec5SDimitry Andric Type *SrcTy = V->getType(); 48480b57cec5SDimitry Andric if (SrcTy->isPtrOrPtrVectorTy() && DestTy->isPtrOrPtrVectorTy() && 48490b57cec5SDimitry Andric SrcTy->getPointerAddressSpace() != DestTy->getPointerAddressSpace()) { 48500b57cec5SDimitry Andric LLVMContext &Context = V->getContext(); 48510b57cec5SDimitry Andric 48520b57cec5SDimitry Andric // We have no information about target data layout, so we assume that 48530b57cec5SDimitry Andric // the maximum pointer size is 64bit. 48540b57cec5SDimitry Andric Type *MidTy = Type::getInt64Ty(Context); 48550b57cec5SDimitry Andric Temp = CastInst::Create(Instruction::PtrToInt, V, MidTy); 48560b57cec5SDimitry Andric 48570b57cec5SDimitry Andric return CastInst::Create(Instruction::IntToPtr, Temp, DestTy); 48580b57cec5SDimitry Andric } 48590b57cec5SDimitry Andric 48600b57cec5SDimitry Andric return nullptr; 48610b57cec5SDimitry Andric } 48620b57cec5SDimitry Andric 486381ad6265SDimitry Andric Constant *llvm::UpgradeBitCastExpr(unsigned Opc, Constant *C, Type *DestTy) { 48640b57cec5SDimitry Andric if (Opc != Instruction::BitCast) 48650b57cec5SDimitry Andric return nullptr; 48660b57cec5SDimitry Andric 48670b57cec5SDimitry Andric Type *SrcTy = C->getType(); 48680b57cec5SDimitry Andric if (SrcTy->isPtrOrPtrVectorTy() && DestTy->isPtrOrPtrVectorTy() && 48690b57cec5SDimitry Andric SrcTy->getPointerAddressSpace() != DestTy->getPointerAddressSpace()) { 48700b57cec5SDimitry Andric LLVMContext &Context = C->getContext(); 48710b57cec5SDimitry Andric 48720b57cec5SDimitry Andric // We have no information about target data layout, so we assume that 48730b57cec5SDimitry Andric // the maximum pointer size is 64bit. 48740b57cec5SDimitry Andric Type *MidTy = Type::getInt64Ty(Context); 48750b57cec5SDimitry Andric 48760b57cec5SDimitry Andric return ConstantExpr::getIntToPtr(ConstantExpr::getPtrToInt(C, MidTy), 48770b57cec5SDimitry Andric DestTy); 48780b57cec5SDimitry Andric } 48790b57cec5SDimitry Andric 48800b57cec5SDimitry Andric return nullptr; 48810b57cec5SDimitry Andric } 48820b57cec5SDimitry Andric 48830b57cec5SDimitry Andric /// Check the debug info version number, if it is out-dated, drop the debug 48840b57cec5SDimitry Andric /// info. Return true if module is modified. 48850b57cec5SDimitry Andric bool llvm::UpgradeDebugInfo(Module &M) { 488606c3fb27SDimitry Andric if (DisableAutoUpgradeDebugInfo) 488706c3fb27SDimitry Andric return false; 488806c3fb27SDimitry Andric 48890b57cec5SDimitry Andric unsigned Version = getDebugMetadataVersionFromModule(M); 48900b57cec5SDimitry Andric if (Version == DEBUG_METADATA_VERSION) { 48910b57cec5SDimitry Andric bool BrokenDebugInfo = false; 48920b57cec5SDimitry Andric if (verifyModule(M, &llvm::errs(), &BrokenDebugInfo)) 48930b57cec5SDimitry Andric report_fatal_error("Broken module found, compilation aborted!"); 48940b57cec5SDimitry Andric if (!BrokenDebugInfo) 48950b57cec5SDimitry Andric // Everything is ok. 48960b57cec5SDimitry Andric return false; 48970b57cec5SDimitry Andric else { 48980b57cec5SDimitry Andric // Diagnose malformed debug info. 48990b57cec5SDimitry Andric DiagnosticInfoIgnoringInvalidDebugMetadata Diag(M); 49000b57cec5SDimitry Andric M.getContext().diagnose(Diag); 49010b57cec5SDimitry Andric } 49020b57cec5SDimitry Andric } 49030b57cec5SDimitry Andric bool Modified = StripDebugInfo(M); 49040b57cec5SDimitry Andric if (Modified && Version != DEBUG_METADATA_VERSION) { 49050b57cec5SDimitry Andric // Diagnose a version mismatch. 49060b57cec5SDimitry Andric DiagnosticInfoDebugMetadataVersion DiagVersion(M, Version); 49070b57cec5SDimitry Andric M.getContext().diagnose(DiagVersion); 49080b57cec5SDimitry Andric } 49090b57cec5SDimitry Andric return Modified; 49100b57cec5SDimitry Andric } 49110b57cec5SDimitry Andric 49128bcb0991SDimitry Andric /// This checks for objc retain release marker which should be upgraded. It 49138bcb0991SDimitry Andric /// returns true if module is modified. 49147a6dacacSDimitry Andric static bool upgradeRetainReleaseMarker(Module &M) { 49150b57cec5SDimitry Andric bool Changed = false; 49160b57cec5SDimitry Andric const char *MarkerKey = "clang.arc.retainAutoreleasedReturnValueMarker"; 49170b57cec5SDimitry Andric NamedMDNode *ModRetainReleaseMarker = M.getNamedMetadata(MarkerKey); 49180b57cec5SDimitry Andric if (ModRetainReleaseMarker) { 49190b57cec5SDimitry Andric MDNode *Op = ModRetainReleaseMarker->getOperand(0); 49200b57cec5SDimitry Andric if (Op) { 49210b57cec5SDimitry Andric MDString *ID = dyn_cast_or_null<MDString>(Op->getOperand(0)); 49220b57cec5SDimitry Andric if (ID) { 49230b57cec5SDimitry Andric SmallVector<StringRef, 4> ValueComp; 49240b57cec5SDimitry Andric ID->getString().split(ValueComp, "#"); 49250b57cec5SDimitry Andric if (ValueComp.size() == 2) { 49260b57cec5SDimitry Andric std::string NewValue = ValueComp[0].str() + ";" + ValueComp[1].str(); 49270b57cec5SDimitry Andric ID = MDString::get(M.getContext(), NewValue); 49280b57cec5SDimitry Andric } 49290b57cec5SDimitry Andric M.addModuleFlag(Module::Error, MarkerKey, ID); 49300b57cec5SDimitry Andric M.eraseNamedMetadata(ModRetainReleaseMarker); 49310b57cec5SDimitry Andric Changed = true; 49320b57cec5SDimitry Andric } 49330b57cec5SDimitry Andric } 49340b57cec5SDimitry Andric } 49350b57cec5SDimitry Andric return Changed; 49360b57cec5SDimitry Andric } 49370b57cec5SDimitry Andric 49388bcb0991SDimitry Andric void llvm::UpgradeARCRuntime(Module &M) { 49398bcb0991SDimitry Andric // This lambda converts normal function calls to ARC runtime functions to 49408bcb0991SDimitry Andric // intrinsic calls. 49418bcb0991SDimitry Andric auto UpgradeToIntrinsic = [&](const char *OldFunc, 49428bcb0991SDimitry Andric llvm::Intrinsic::ID IntrinsicFunc) { 49438bcb0991SDimitry Andric Function *Fn = M.getFunction(OldFunc); 49448bcb0991SDimitry Andric 49458bcb0991SDimitry Andric if (!Fn) 49468bcb0991SDimitry Andric return; 49478bcb0991SDimitry Andric 49488bcb0991SDimitry Andric Function *NewFn = llvm::Intrinsic::getDeclaration(&M, IntrinsicFunc); 49498bcb0991SDimitry Andric 4950e8d8bef9SDimitry Andric for (User *U : make_early_inc_range(Fn->users())) { 4951e8d8bef9SDimitry Andric CallInst *CI = dyn_cast<CallInst>(U); 49528bcb0991SDimitry Andric if (!CI || CI->getCalledFunction() != Fn) 49538bcb0991SDimitry Andric continue; 49548bcb0991SDimitry Andric 49558bcb0991SDimitry Andric IRBuilder<> Builder(CI->getParent(), CI->getIterator()); 49568bcb0991SDimitry Andric FunctionType *NewFuncTy = NewFn->getFunctionType(); 49578bcb0991SDimitry Andric SmallVector<Value *, 2> Args; 49588bcb0991SDimitry Andric 4959480093f4SDimitry Andric // Don't upgrade the intrinsic if it's not valid to bitcast the return 4960480093f4SDimitry Andric // value to the return type of the old function. 4961480093f4SDimitry Andric if (NewFuncTy->getReturnType() != CI->getType() && 4962480093f4SDimitry Andric !CastInst::castIsValid(Instruction::BitCast, CI, 4963480093f4SDimitry Andric NewFuncTy->getReturnType())) 4964480093f4SDimitry Andric continue; 4965480093f4SDimitry Andric 4966480093f4SDimitry Andric bool InvalidCast = false; 4967480093f4SDimitry Andric 4968349cc55cSDimitry Andric for (unsigned I = 0, E = CI->arg_size(); I != E; ++I) { 49698bcb0991SDimitry Andric Value *Arg = CI->getArgOperand(I); 4970480093f4SDimitry Andric 49718bcb0991SDimitry Andric // Bitcast argument to the parameter type of the new function if it's 49728bcb0991SDimitry Andric // not a variadic argument. 4973480093f4SDimitry Andric if (I < NewFuncTy->getNumParams()) { 4974480093f4SDimitry Andric // Don't upgrade the intrinsic if it's not valid to bitcast the argument 4975480093f4SDimitry Andric // to the parameter type of the new function. 4976480093f4SDimitry Andric if (!CastInst::castIsValid(Instruction::BitCast, Arg, 4977480093f4SDimitry Andric NewFuncTy->getParamType(I))) { 4978480093f4SDimitry Andric InvalidCast = true; 4979480093f4SDimitry Andric break; 4980480093f4SDimitry Andric } 49818bcb0991SDimitry Andric Arg = Builder.CreateBitCast(Arg, NewFuncTy->getParamType(I)); 4982480093f4SDimitry Andric } 49838bcb0991SDimitry Andric Args.push_back(Arg); 49848bcb0991SDimitry Andric } 49858bcb0991SDimitry Andric 4986480093f4SDimitry Andric if (InvalidCast) 4987480093f4SDimitry Andric continue; 4988480093f4SDimitry Andric 49898bcb0991SDimitry Andric // Create a call instruction that calls the new function. 49908bcb0991SDimitry Andric CallInst *NewCall = Builder.CreateCall(NewFuncTy, NewFn, Args); 49918bcb0991SDimitry Andric NewCall->setTailCallKind(cast<CallInst>(CI)->getTailCallKind()); 4992e8d8bef9SDimitry Andric NewCall->takeName(CI); 49938bcb0991SDimitry Andric 49948bcb0991SDimitry Andric // Bitcast the return value back to the type of the old call. 49958bcb0991SDimitry Andric Value *NewRetVal = Builder.CreateBitCast(NewCall, CI->getType()); 49968bcb0991SDimitry Andric 49978bcb0991SDimitry Andric if (!CI->use_empty()) 49988bcb0991SDimitry Andric CI->replaceAllUsesWith(NewRetVal); 49998bcb0991SDimitry Andric CI->eraseFromParent(); 50008bcb0991SDimitry Andric } 50018bcb0991SDimitry Andric 50028bcb0991SDimitry Andric if (Fn->use_empty()) 50038bcb0991SDimitry Andric Fn->eraseFromParent(); 50048bcb0991SDimitry Andric }; 50058bcb0991SDimitry Andric 50068bcb0991SDimitry Andric // Unconditionally convert a call to "clang.arc.use" to a call to 50078bcb0991SDimitry Andric // "llvm.objc.clang.arc.use". 50088bcb0991SDimitry Andric UpgradeToIntrinsic("clang.arc.use", llvm::Intrinsic::objc_clang_arc_use); 50098bcb0991SDimitry Andric 50108bcb0991SDimitry Andric // Upgrade the retain release marker. If there is no need to upgrade 50118bcb0991SDimitry Andric // the marker, that means either the module is already new enough to contain 50128bcb0991SDimitry Andric // new intrinsics or it is not ARC. There is no need to upgrade runtime call. 50137a6dacacSDimitry Andric if (!upgradeRetainReleaseMarker(M)) 50148bcb0991SDimitry Andric return; 50158bcb0991SDimitry Andric 50168bcb0991SDimitry Andric std::pair<const char *, llvm::Intrinsic::ID> RuntimeFuncs[] = { 50178bcb0991SDimitry Andric {"objc_autorelease", llvm::Intrinsic::objc_autorelease}, 50188bcb0991SDimitry Andric {"objc_autoreleasePoolPop", llvm::Intrinsic::objc_autoreleasePoolPop}, 50198bcb0991SDimitry Andric {"objc_autoreleasePoolPush", llvm::Intrinsic::objc_autoreleasePoolPush}, 50208bcb0991SDimitry Andric {"objc_autoreleaseReturnValue", 50218bcb0991SDimitry Andric llvm::Intrinsic::objc_autoreleaseReturnValue}, 50228bcb0991SDimitry Andric {"objc_copyWeak", llvm::Intrinsic::objc_copyWeak}, 50238bcb0991SDimitry Andric {"objc_destroyWeak", llvm::Intrinsic::objc_destroyWeak}, 50248bcb0991SDimitry Andric {"objc_initWeak", llvm::Intrinsic::objc_initWeak}, 50258bcb0991SDimitry Andric {"objc_loadWeak", llvm::Intrinsic::objc_loadWeak}, 50268bcb0991SDimitry Andric {"objc_loadWeakRetained", llvm::Intrinsic::objc_loadWeakRetained}, 50278bcb0991SDimitry Andric {"objc_moveWeak", llvm::Intrinsic::objc_moveWeak}, 50288bcb0991SDimitry Andric {"objc_release", llvm::Intrinsic::objc_release}, 50298bcb0991SDimitry Andric {"objc_retain", llvm::Intrinsic::objc_retain}, 50308bcb0991SDimitry Andric {"objc_retainAutorelease", llvm::Intrinsic::objc_retainAutorelease}, 50318bcb0991SDimitry Andric {"objc_retainAutoreleaseReturnValue", 50328bcb0991SDimitry Andric llvm::Intrinsic::objc_retainAutoreleaseReturnValue}, 50338bcb0991SDimitry Andric {"objc_retainAutoreleasedReturnValue", 50348bcb0991SDimitry Andric llvm::Intrinsic::objc_retainAutoreleasedReturnValue}, 50358bcb0991SDimitry Andric {"objc_retainBlock", llvm::Intrinsic::objc_retainBlock}, 50368bcb0991SDimitry Andric {"objc_storeStrong", llvm::Intrinsic::objc_storeStrong}, 50378bcb0991SDimitry Andric {"objc_storeWeak", llvm::Intrinsic::objc_storeWeak}, 50388bcb0991SDimitry Andric {"objc_unsafeClaimAutoreleasedReturnValue", 50398bcb0991SDimitry Andric llvm::Intrinsic::objc_unsafeClaimAutoreleasedReturnValue}, 50408bcb0991SDimitry Andric {"objc_retainedObject", llvm::Intrinsic::objc_retainedObject}, 50418bcb0991SDimitry Andric {"objc_unretainedObject", llvm::Intrinsic::objc_unretainedObject}, 50428bcb0991SDimitry Andric {"objc_unretainedPointer", llvm::Intrinsic::objc_unretainedPointer}, 50438bcb0991SDimitry Andric {"objc_retain_autorelease", llvm::Intrinsic::objc_retain_autorelease}, 50448bcb0991SDimitry Andric {"objc_sync_enter", llvm::Intrinsic::objc_sync_enter}, 50458bcb0991SDimitry Andric {"objc_sync_exit", llvm::Intrinsic::objc_sync_exit}, 50468bcb0991SDimitry Andric {"objc_arc_annotation_topdown_bbstart", 50478bcb0991SDimitry Andric llvm::Intrinsic::objc_arc_annotation_topdown_bbstart}, 50488bcb0991SDimitry Andric {"objc_arc_annotation_topdown_bbend", 50498bcb0991SDimitry Andric llvm::Intrinsic::objc_arc_annotation_topdown_bbend}, 50508bcb0991SDimitry Andric {"objc_arc_annotation_bottomup_bbstart", 50518bcb0991SDimitry Andric llvm::Intrinsic::objc_arc_annotation_bottomup_bbstart}, 50528bcb0991SDimitry Andric {"objc_arc_annotation_bottomup_bbend", 50538bcb0991SDimitry Andric llvm::Intrinsic::objc_arc_annotation_bottomup_bbend}}; 50548bcb0991SDimitry Andric 50558bcb0991SDimitry Andric for (auto &I : RuntimeFuncs) 50568bcb0991SDimitry Andric UpgradeToIntrinsic(I.first, I.second); 50578bcb0991SDimitry Andric } 50588bcb0991SDimitry Andric 50590b57cec5SDimitry Andric bool llvm::UpgradeModuleFlags(Module &M) { 50600b57cec5SDimitry Andric NamedMDNode *ModFlags = M.getModuleFlagsMetadata(); 50610b57cec5SDimitry Andric if (!ModFlags) 50620b57cec5SDimitry Andric return false; 50630b57cec5SDimitry Andric 50640b57cec5SDimitry Andric bool HasObjCFlag = false, HasClassProperties = false, Changed = false; 50655ffd83dbSDimitry Andric bool HasSwiftVersionFlag = false; 50665ffd83dbSDimitry Andric uint8_t SwiftMajorVersion, SwiftMinorVersion; 50675ffd83dbSDimitry Andric uint32_t SwiftABIVersion; 50685ffd83dbSDimitry Andric auto Int8Ty = Type::getInt8Ty(M.getContext()); 50695ffd83dbSDimitry Andric auto Int32Ty = Type::getInt32Ty(M.getContext()); 50705ffd83dbSDimitry Andric 50710b57cec5SDimitry Andric for (unsigned I = 0, E = ModFlags->getNumOperands(); I != E; ++I) { 50720b57cec5SDimitry Andric MDNode *Op = ModFlags->getOperand(I); 50730b57cec5SDimitry Andric if (Op->getNumOperands() != 3) 50740b57cec5SDimitry Andric continue; 50750b57cec5SDimitry Andric MDString *ID = dyn_cast_or_null<MDString>(Op->getOperand(1)); 50760b57cec5SDimitry Andric if (!ID) 50770b57cec5SDimitry Andric continue; 5078bdd1243dSDimitry Andric auto SetBehavior = [&](Module::ModFlagBehavior B) { 5079bdd1243dSDimitry Andric Metadata *Ops[3] = {ConstantAsMetadata::get(ConstantInt::get( 5080bdd1243dSDimitry Andric Type::getInt32Ty(M.getContext()), B)), 50810b57cec5SDimitry Andric MDString::get(M.getContext(), ID->getString()), 50820b57cec5SDimitry Andric Op->getOperand(2)}; 50830b57cec5SDimitry Andric ModFlags->setOperand(I, MDNode::get(M.getContext(), Ops)); 50840b57cec5SDimitry Andric Changed = true; 5085bdd1243dSDimitry Andric }; 5086bdd1243dSDimitry Andric 5087bdd1243dSDimitry Andric if (ID->getString() == "Objective-C Image Info Version") 5088bdd1243dSDimitry Andric HasObjCFlag = true; 5089bdd1243dSDimitry Andric if (ID->getString() == "Objective-C Class Properties") 5090bdd1243dSDimitry Andric HasClassProperties = true; 5091bdd1243dSDimitry Andric // Upgrade PIC from Error/Max to Min. 5092bdd1243dSDimitry Andric if (ID->getString() == "PIC Level") { 5093bdd1243dSDimitry Andric if (auto *Behavior = 5094bdd1243dSDimitry Andric mdconst::dyn_extract_or_null<ConstantInt>(Op->getOperand(0))) { 5095bdd1243dSDimitry Andric uint64_t V = Behavior->getLimitedValue(); 5096bdd1243dSDimitry Andric if (V == Module::Error || V == Module::Max) 5097bdd1243dSDimitry Andric SetBehavior(Module::Min); 50980b57cec5SDimitry Andric } 50990b57cec5SDimitry Andric } 5100bdd1243dSDimitry Andric // Upgrade "PIE Level" from Error to Max. 5101bdd1243dSDimitry Andric if (ID->getString() == "PIE Level") 5102bdd1243dSDimitry Andric if (auto *Behavior = 5103bdd1243dSDimitry Andric mdconst::dyn_extract_or_null<ConstantInt>(Op->getOperand(0))) 5104bdd1243dSDimitry Andric if (Behavior->getLimitedValue() == Module::Error) 5105bdd1243dSDimitry Andric SetBehavior(Module::Max); 510681ad6265SDimitry Andric 510781ad6265SDimitry Andric // Upgrade branch protection and return address signing module flags. The 510881ad6265SDimitry Andric // module flag behavior for these fields were Error and now they are Min. 510981ad6265SDimitry Andric if (ID->getString() == "branch-target-enforcement" || 51105f757f3fSDimitry Andric ID->getString().starts_with("sign-return-address")) { 511181ad6265SDimitry Andric if (auto *Behavior = 511281ad6265SDimitry Andric mdconst::dyn_extract_or_null<ConstantInt>(Op->getOperand(0))) { 511381ad6265SDimitry Andric if (Behavior->getLimitedValue() == Module::Error) { 511481ad6265SDimitry Andric Type *Int32Ty = Type::getInt32Ty(M.getContext()); 511581ad6265SDimitry Andric Metadata *Ops[3] = { 511681ad6265SDimitry Andric ConstantAsMetadata::get(ConstantInt::get(Int32Ty, Module::Min)), 511781ad6265SDimitry Andric Op->getOperand(1), Op->getOperand(2)}; 511881ad6265SDimitry Andric ModFlags->setOperand(I, MDNode::get(M.getContext(), Ops)); 511981ad6265SDimitry Andric Changed = true; 512081ad6265SDimitry Andric } 512181ad6265SDimitry Andric } 512281ad6265SDimitry Andric } 512381ad6265SDimitry Andric 51240b57cec5SDimitry Andric // Upgrade Objective-C Image Info Section. Removed the whitespce in the 51250b57cec5SDimitry Andric // section name so that llvm-lto will not complain about mismatching 51260b57cec5SDimitry Andric // module flags that is functionally the same. 51270b57cec5SDimitry Andric if (ID->getString() == "Objective-C Image Info Section") { 51280b57cec5SDimitry Andric if (auto *Value = dyn_cast_or_null<MDString>(Op->getOperand(2))) { 51290b57cec5SDimitry Andric SmallVector<StringRef, 4> ValueComp; 51300b57cec5SDimitry Andric Value->getString().split(ValueComp, " "); 51310b57cec5SDimitry Andric if (ValueComp.size() != 1) { 51320b57cec5SDimitry Andric std::string NewValue; 51330b57cec5SDimitry Andric for (auto &S : ValueComp) 51340b57cec5SDimitry Andric NewValue += S.str(); 51350b57cec5SDimitry Andric Metadata *Ops[3] = {Op->getOperand(0), Op->getOperand(1), 51360b57cec5SDimitry Andric MDString::get(M.getContext(), NewValue)}; 51370b57cec5SDimitry Andric ModFlags->setOperand(I, MDNode::get(M.getContext(), Ops)); 51380b57cec5SDimitry Andric Changed = true; 51390b57cec5SDimitry Andric } 51400b57cec5SDimitry Andric } 51410b57cec5SDimitry Andric } 51425ffd83dbSDimitry Andric 51435ffd83dbSDimitry Andric // IRUpgrader turns a i32 type "Objective-C Garbage Collection" into i8 value. 51445ffd83dbSDimitry Andric // If the higher bits are set, it adds new module flag for swift info. 51455ffd83dbSDimitry Andric if (ID->getString() == "Objective-C Garbage Collection") { 51465ffd83dbSDimitry Andric auto Md = dyn_cast<ConstantAsMetadata>(Op->getOperand(2)); 51475ffd83dbSDimitry Andric if (Md) { 51485ffd83dbSDimitry Andric assert(Md->getValue() && "Expected non-empty metadata"); 51495ffd83dbSDimitry Andric auto Type = Md->getValue()->getType(); 51505ffd83dbSDimitry Andric if (Type == Int8Ty) 51515ffd83dbSDimitry Andric continue; 51525ffd83dbSDimitry Andric unsigned Val = Md->getValue()->getUniqueInteger().getZExtValue(); 51535ffd83dbSDimitry Andric if ((Val & 0xff) != Val) { 51545ffd83dbSDimitry Andric HasSwiftVersionFlag = true; 51555ffd83dbSDimitry Andric SwiftABIVersion = (Val & 0xff00) >> 8; 51565ffd83dbSDimitry Andric SwiftMajorVersion = (Val & 0xff000000) >> 24; 51575ffd83dbSDimitry Andric SwiftMinorVersion = (Val & 0xff0000) >> 16; 51585ffd83dbSDimitry Andric } 51595ffd83dbSDimitry Andric Metadata *Ops[3] = { 51605ffd83dbSDimitry Andric ConstantAsMetadata::get(ConstantInt::get(Int32Ty,Module::Error)), 51615ffd83dbSDimitry Andric Op->getOperand(1), 51625ffd83dbSDimitry Andric ConstantAsMetadata::get(ConstantInt::get(Int8Ty,Val & 0xff))}; 51635ffd83dbSDimitry Andric ModFlags->setOperand(I, MDNode::get(M.getContext(), Ops)); 51645ffd83dbSDimitry Andric Changed = true; 51655ffd83dbSDimitry Andric } 51665ffd83dbSDimitry Andric } 5167*0fca6ea1SDimitry Andric 5168*0fca6ea1SDimitry Andric if (ID->getString() == "amdgpu_code_object_version") { 5169*0fca6ea1SDimitry Andric Metadata *Ops[3] = { 5170*0fca6ea1SDimitry Andric Op->getOperand(0), 5171*0fca6ea1SDimitry Andric MDString::get(M.getContext(), "amdhsa_code_object_version"), 5172*0fca6ea1SDimitry Andric Op->getOperand(2)}; 5173*0fca6ea1SDimitry Andric ModFlags->setOperand(I, MDNode::get(M.getContext(), Ops)); 5174*0fca6ea1SDimitry Andric Changed = true; 5175*0fca6ea1SDimitry Andric } 51760b57cec5SDimitry Andric } 51770b57cec5SDimitry Andric 51780b57cec5SDimitry Andric // "Objective-C Class Properties" is recently added for Objective-C. We 51790b57cec5SDimitry Andric // upgrade ObjC bitcodes to contain a "Objective-C Class Properties" module 51800b57cec5SDimitry Andric // flag of value 0, so we can correclty downgrade this flag when trying to 51810b57cec5SDimitry Andric // link an ObjC bitcode without this module flag with an ObjC bitcode with 51820b57cec5SDimitry Andric // this module flag. 51830b57cec5SDimitry Andric if (HasObjCFlag && !HasClassProperties) { 51840b57cec5SDimitry Andric M.addModuleFlag(llvm::Module::Override, "Objective-C Class Properties", 51850b57cec5SDimitry Andric (uint32_t)0); 51860b57cec5SDimitry Andric Changed = true; 51870b57cec5SDimitry Andric } 51880b57cec5SDimitry Andric 51895ffd83dbSDimitry Andric if (HasSwiftVersionFlag) { 51905ffd83dbSDimitry Andric M.addModuleFlag(Module::Error, "Swift ABI Version", 51915ffd83dbSDimitry Andric SwiftABIVersion); 51925ffd83dbSDimitry Andric M.addModuleFlag(Module::Error, "Swift Major Version", 51935ffd83dbSDimitry Andric ConstantInt::get(Int8Ty, SwiftMajorVersion)); 51945ffd83dbSDimitry Andric M.addModuleFlag(Module::Error, "Swift Minor Version", 51955ffd83dbSDimitry Andric ConstantInt::get(Int8Ty, SwiftMinorVersion)); 51965ffd83dbSDimitry Andric Changed = true; 51975ffd83dbSDimitry Andric } 51985ffd83dbSDimitry Andric 51990b57cec5SDimitry Andric return Changed; 52000b57cec5SDimitry Andric } 52010b57cec5SDimitry Andric 52020b57cec5SDimitry Andric void llvm::UpgradeSectionAttributes(Module &M) { 52030b57cec5SDimitry Andric auto TrimSpaces = [](StringRef Section) -> std::string { 52040b57cec5SDimitry Andric SmallVector<StringRef, 5> Components; 52050b57cec5SDimitry Andric Section.split(Components, ','); 52060b57cec5SDimitry Andric 52070b57cec5SDimitry Andric SmallString<32> Buffer; 52080b57cec5SDimitry Andric raw_svector_ostream OS(Buffer); 52090b57cec5SDimitry Andric 52100b57cec5SDimitry Andric for (auto Component : Components) 52110b57cec5SDimitry Andric OS << ',' << Component.trim(); 52120b57cec5SDimitry Andric 52135ffd83dbSDimitry Andric return std::string(OS.str().substr(1)); 52140b57cec5SDimitry Andric }; 52150b57cec5SDimitry Andric 52160b57cec5SDimitry Andric for (auto &GV : M.globals()) { 52170b57cec5SDimitry Andric if (!GV.hasSection()) 52180b57cec5SDimitry Andric continue; 52190b57cec5SDimitry Andric 52200b57cec5SDimitry Andric StringRef Section = GV.getSection(); 52210b57cec5SDimitry Andric 52225f757f3fSDimitry Andric if (!Section.starts_with("__DATA, __objc_catlist")) 52230b57cec5SDimitry Andric continue; 52240b57cec5SDimitry Andric 52250b57cec5SDimitry Andric // __DATA, __objc_catlist, regular, no_dead_strip 52260b57cec5SDimitry Andric // __DATA,__objc_catlist,regular,no_dead_strip 52270b57cec5SDimitry Andric GV.setSection(TrimSpaces(Section)); 52280b57cec5SDimitry Andric } 52290b57cec5SDimitry Andric } 52300b57cec5SDimitry Andric 52315ffd83dbSDimitry Andric namespace { 52325ffd83dbSDimitry Andric // Prior to LLVM 10.0, the strictfp attribute could be used on individual 52335ffd83dbSDimitry Andric // callsites within a function that did not also have the strictfp attribute. 52345ffd83dbSDimitry Andric // Since 10.0, if strict FP semantics are needed within a function, the 52355ffd83dbSDimitry Andric // function must have the strictfp attribute and all calls within the function 52365ffd83dbSDimitry Andric // must also have the strictfp attribute. This latter restriction is 52375ffd83dbSDimitry Andric // necessary to prevent unwanted libcall simplification when a function is 52385ffd83dbSDimitry Andric // being cloned (such as for inlining). 52395ffd83dbSDimitry Andric // 52405ffd83dbSDimitry Andric // The "dangling" strictfp attribute usage was only used to prevent constant 52415ffd83dbSDimitry Andric // folding and other libcall simplification. The nobuiltin attribute on the 52425ffd83dbSDimitry Andric // callsite has the same effect. 52435ffd83dbSDimitry Andric struct StrictFPUpgradeVisitor : public InstVisitor<StrictFPUpgradeVisitor> { 524481ad6265SDimitry Andric StrictFPUpgradeVisitor() = default; 52455ffd83dbSDimitry Andric 52465ffd83dbSDimitry Andric void visitCallBase(CallBase &Call) { 52475ffd83dbSDimitry Andric if (!Call.isStrictFP()) 52485ffd83dbSDimitry Andric return; 52495ffd83dbSDimitry Andric if (isa<ConstrainedFPIntrinsic>(&Call)) 52505ffd83dbSDimitry Andric return; 52515ffd83dbSDimitry Andric // If we get here, the caller doesn't have the strictfp attribute 52525ffd83dbSDimitry Andric // but this callsite does. Replace the strictfp attribute with nobuiltin. 5253349cc55cSDimitry Andric Call.removeFnAttr(Attribute::StrictFP); 5254349cc55cSDimitry Andric Call.addFnAttr(Attribute::NoBuiltin); 52555ffd83dbSDimitry Andric } 52565ffd83dbSDimitry Andric }; 52575ffd83dbSDimitry Andric } // namespace 52585ffd83dbSDimitry Andric 52595ffd83dbSDimitry Andric void llvm::UpgradeFunctionAttributes(Function &F) { 52605ffd83dbSDimitry Andric // If a function definition doesn't have the strictfp attribute, 52615ffd83dbSDimitry Andric // convert any callsite strictfp attributes to nobuiltin. 52625ffd83dbSDimitry Andric if (!F.isDeclaration() && !F.hasFnAttribute(Attribute::StrictFP)) { 52635ffd83dbSDimitry Andric StrictFPUpgradeVisitor SFPV; 52645ffd83dbSDimitry Andric SFPV.visit(F); 52655ffd83dbSDimitry Andric } 5266e8d8bef9SDimitry Andric 5267fe6060f1SDimitry Andric // Remove all incompatibile attributes from function. 5268349cc55cSDimitry Andric F.removeRetAttrs(AttributeFuncs::typeIncompatible(F.getReturnType())); 5269fe6060f1SDimitry Andric for (auto &Arg : F.args()) 5270fe6060f1SDimitry Andric Arg.removeAttrs(AttributeFuncs::typeIncompatible(Arg.getType())); 5271*0fca6ea1SDimitry Andric 5272*0fca6ea1SDimitry Andric // Older versions of LLVM treated an "implicit-section-name" attribute 5273*0fca6ea1SDimitry Andric // similarly to directly setting the section on a Function. 5274*0fca6ea1SDimitry Andric if (Attribute A = F.getFnAttribute("implicit-section-name"); 5275*0fca6ea1SDimitry Andric A.isValid() && A.isStringAttribute()) { 5276*0fca6ea1SDimitry Andric F.setSection(A.getValueAsString()); 5277*0fca6ea1SDimitry Andric F.removeFnAttr("implicit-section-name"); 5278*0fca6ea1SDimitry Andric } 52795ffd83dbSDimitry Andric } 52805ffd83dbSDimitry Andric 52810b57cec5SDimitry Andric static bool isOldLoopArgument(Metadata *MD) { 52820b57cec5SDimitry Andric auto *T = dyn_cast_or_null<MDTuple>(MD); 52830b57cec5SDimitry Andric if (!T) 52840b57cec5SDimitry Andric return false; 52850b57cec5SDimitry Andric if (T->getNumOperands() < 1) 52860b57cec5SDimitry Andric return false; 52870b57cec5SDimitry Andric auto *S = dyn_cast_or_null<MDString>(T->getOperand(0)); 52880b57cec5SDimitry Andric if (!S) 52890b57cec5SDimitry Andric return false; 52905f757f3fSDimitry Andric return S->getString().starts_with("llvm.vectorizer."); 52910b57cec5SDimitry Andric } 52920b57cec5SDimitry Andric 52930b57cec5SDimitry Andric static MDString *upgradeLoopTag(LLVMContext &C, StringRef OldTag) { 52940b57cec5SDimitry Andric StringRef OldPrefix = "llvm.vectorizer."; 52955f757f3fSDimitry Andric assert(OldTag.starts_with(OldPrefix) && "Expected old prefix"); 52960b57cec5SDimitry Andric 52970b57cec5SDimitry Andric if (OldTag == "llvm.vectorizer.unroll") 52980b57cec5SDimitry Andric return MDString::get(C, "llvm.loop.interleave.count"); 52990b57cec5SDimitry Andric 53000b57cec5SDimitry Andric return MDString::get( 53010b57cec5SDimitry Andric C, (Twine("llvm.loop.vectorize.") + OldTag.drop_front(OldPrefix.size())) 53020b57cec5SDimitry Andric .str()); 53030b57cec5SDimitry Andric } 53040b57cec5SDimitry Andric 53050b57cec5SDimitry Andric static Metadata *upgradeLoopArgument(Metadata *MD) { 53060b57cec5SDimitry Andric auto *T = dyn_cast_or_null<MDTuple>(MD); 53070b57cec5SDimitry Andric if (!T) 53080b57cec5SDimitry Andric return MD; 53090b57cec5SDimitry Andric if (T->getNumOperands() < 1) 53100b57cec5SDimitry Andric return MD; 53110b57cec5SDimitry Andric auto *OldTag = dyn_cast_or_null<MDString>(T->getOperand(0)); 53120b57cec5SDimitry Andric if (!OldTag) 53130b57cec5SDimitry Andric return MD; 53145f757f3fSDimitry Andric if (!OldTag->getString().starts_with("llvm.vectorizer.")) 53150b57cec5SDimitry Andric return MD; 53160b57cec5SDimitry Andric 53170b57cec5SDimitry Andric // This has an old tag. Upgrade it. 53180b57cec5SDimitry Andric SmallVector<Metadata *, 8> Ops; 53190b57cec5SDimitry Andric Ops.reserve(T->getNumOperands()); 53200b57cec5SDimitry Andric Ops.push_back(upgradeLoopTag(T->getContext(), OldTag->getString())); 53210b57cec5SDimitry Andric for (unsigned I = 1, E = T->getNumOperands(); I != E; ++I) 53220b57cec5SDimitry Andric Ops.push_back(T->getOperand(I)); 53230b57cec5SDimitry Andric 53240b57cec5SDimitry Andric return MDTuple::get(T->getContext(), Ops); 53250b57cec5SDimitry Andric } 53260b57cec5SDimitry Andric 53270b57cec5SDimitry Andric MDNode *llvm::upgradeInstructionLoopAttachment(MDNode &N) { 53280b57cec5SDimitry Andric auto *T = dyn_cast<MDTuple>(&N); 53290b57cec5SDimitry Andric if (!T) 53300b57cec5SDimitry Andric return &N; 53310b57cec5SDimitry Andric 53320b57cec5SDimitry Andric if (none_of(T->operands(), isOldLoopArgument)) 53330b57cec5SDimitry Andric return &N; 53340b57cec5SDimitry Andric 53350b57cec5SDimitry Andric SmallVector<Metadata *, 8> Ops; 53360b57cec5SDimitry Andric Ops.reserve(T->getNumOperands()); 53370b57cec5SDimitry Andric for (Metadata *MD : T->operands()) 53380b57cec5SDimitry Andric Ops.push_back(upgradeLoopArgument(MD)); 53390b57cec5SDimitry Andric 53400b57cec5SDimitry Andric return MDTuple::get(T->getContext(), Ops); 53410b57cec5SDimitry Andric } 53428bcb0991SDimitry Andric 53438bcb0991SDimitry Andric std::string llvm::UpgradeDataLayoutString(StringRef DL, StringRef TT) { 5344e8d8bef9SDimitry Andric Triple T(TT); 5345*0fca6ea1SDimitry Andric // The only data layout upgrades needed for pre-GCN, SPIR or SPIRV are setting 5346*0fca6ea1SDimitry Andric // the address space of globals to 1. This does not apply to SPIRV Logical. 5347*0fca6ea1SDimitry Andric if (((T.isAMDGPU() && !T.isAMDGCN()) || 5348*0fca6ea1SDimitry Andric (T.isSPIR() || (T.isSPIRV() && !T.isSPIRVLogical()))) && 5349*0fca6ea1SDimitry Andric !DL.contains("-G") && !DL.starts_with("G")) { 5350e8d8bef9SDimitry Andric return DL.empty() ? std::string("G1") : (DL + "-G1").str(); 5351e8d8bef9SDimitry Andric } 53528bcb0991SDimitry Andric 5353*0fca6ea1SDimitry Andric if (T.isLoongArch64() || T.isRISCV64()) { 5354*0fca6ea1SDimitry Andric // Make i32 a native type for 64-bit LoongArch and RISC-V. 5355bdd1243dSDimitry Andric auto I = DL.find("-n64-"); 5356bdd1243dSDimitry Andric if (I != StringRef::npos) 5357bdd1243dSDimitry Andric return (DL.take_front(I) + "-n32:64-" + DL.drop_front(I + 5)).str(); 5358bdd1243dSDimitry Andric return DL.str(); 5359bdd1243dSDimitry Andric } 5360bdd1243dSDimitry Andric 536104eeddc0SDimitry Andric std::string Res = DL.str(); 536206c3fb27SDimitry Andric // AMDGCN data layout upgrades. 536306c3fb27SDimitry Andric if (T.isAMDGCN()) { 536406c3fb27SDimitry Andric // Define address spaces for constants. 536506c3fb27SDimitry Andric if (!DL.contains("-G") && !DL.starts_with("G")) 536606c3fb27SDimitry Andric Res.append(Res.empty() ? "G1" : "-G1"); 536706c3fb27SDimitry Andric 536806c3fb27SDimitry Andric // Add missing non-integral declarations. 536906c3fb27SDimitry Andric // This goes before adding new address spaces to prevent incoherent string 537006c3fb27SDimitry Andric // values. 53715f757f3fSDimitry Andric if (!DL.contains("-ni") && !DL.starts_with("ni")) 53725f757f3fSDimitry Andric Res.append("-ni:7:8:9"); 53735f757f3fSDimitry Andric // Update ni:7 to ni:7:8:9. 537406c3fb27SDimitry Andric if (DL.ends_with("ni:7")) 53755f757f3fSDimitry Andric Res.append(":8:9"); 53765f757f3fSDimitry Andric if (DL.ends_with("ni:7:8")) 53775f757f3fSDimitry Andric Res.append(":9"); 537806c3fb27SDimitry Andric 537906c3fb27SDimitry Andric // Add sizing for address spaces 7 and 8 (fat raw buffers and buffer 538006c3fb27SDimitry Andric // resources) An empty data layout has already been upgraded to G1 by now. 53815f757f3fSDimitry Andric if (!DL.contains("-p7") && !DL.starts_with("p7")) 538206c3fb27SDimitry Andric Res.append("-p7:160:256:256:32"); 53835f757f3fSDimitry Andric if (!DL.contains("-p8") && !DL.starts_with("p8")) 538406c3fb27SDimitry Andric Res.append("-p8:128:128"); 53855f757f3fSDimitry Andric if (!DL.contains("-p9") && !DL.starts_with("p9")) 53865f757f3fSDimitry Andric Res.append("-p9:192:256:256:32"); 538706c3fb27SDimitry Andric 538806c3fb27SDimitry Andric return Res; 538906c3fb27SDimitry Andric } 539006c3fb27SDimitry Andric 5391*0fca6ea1SDimitry Andric // AArch64 data layout upgrades. 5392*0fca6ea1SDimitry Andric if (T.isAArch64()) { 5393*0fca6ea1SDimitry Andric // Add "-Fn32" 5394*0fca6ea1SDimitry Andric if (!DL.empty() && !DL.contains("-Fn32")) 5395*0fca6ea1SDimitry Andric Res.append("-Fn32"); 5396*0fca6ea1SDimitry Andric return Res; 5397*0fca6ea1SDimitry Andric } 5398*0fca6ea1SDimitry Andric 539904eeddc0SDimitry Andric if (!T.isX86()) 540004eeddc0SDimitry Andric return Res; 54018bcb0991SDimitry Andric 540204eeddc0SDimitry Andric // If the datalayout matches the expected format, add pointer size address 540304eeddc0SDimitry Andric // spaces to the datalayout. 540404eeddc0SDimitry Andric std::string AddrSpaces = "-p270:32:32-p271:32:32-p272:64:64"; 54055f757f3fSDimitry Andric if (StringRef Ref = Res; !Ref.contains(AddrSpaces)) { 54068bcb0991SDimitry Andric SmallVector<StringRef, 4> Groups; 54078bcb0991SDimitry Andric Regex R("(e-m:[a-z](-p:32:32)?)(-[if]64:.*$)"); 54085f757f3fSDimitry Andric if (R.match(Res, &Groups)) 540904eeddc0SDimitry Andric Res = (Groups[1] + AddrSpaces + Groups[3]).str(); 541004eeddc0SDimitry Andric } 54118bcb0991SDimitry Andric 54125f757f3fSDimitry Andric // i128 values need to be 16-byte-aligned. LLVM already called into libgcc 54135f757f3fSDimitry Andric // for i128 operations prior to this being reflected in the data layout, and 54145f757f3fSDimitry Andric // clang mostly produced LLVM IR that already aligned i128 to 16 byte 54155f757f3fSDimitry Andric // boundaries, so although this is a breaking change, the upgrade is expected 54165f757f3fSDimitry Andric // to fix more IR than it breaks. 54175f757f3fSDimitry Andric // Intel MCU is an exception and uses 4-byte-alignment. 54185f757f3fSDimitry Andric if (!T.isOSIAMCU()) { 54195f757f3fSDimitry Andric std::string I128 = "-i128:128"; 54205f757f3fSDimitry Andric if (StringRef Ref = Res; !Ref.contains(I128)) { 54215f757f3fSDimitry Andric SmallVector<StringRef, 4> Groups; 54225f757f3fSDimitry Andric Regex R("^(e(-[mpi][^-]*)*)((-[^mpi][^-]*)*)$"); 54235f757f3fSDimitry Andric if (R.match(Res, &Groups)) 54245f757f3fSDimitry Andric Res = (Groups[1] + I128 + Groups[3]).str(); 54255f757f3fSDimitry Andric } 54265f757f3fSDimitry Andric } 54275f757f3fSDimitry Andric 542804eeddc0SDimitry Andric // For 32-bit MSVC targets, raise the alignment of f80 values to 16 bytes. 542904eeddc0SDimitry Andric // Raising the alignment is safe because Clang did not produce f80 values in 543004eeddc0SDimitry Andric // the MSVC environment before this upgrade was added. 543104eeddc0SDimitry Andric if (T.isWindowsMSVCEnvironment() && !T.isArch64Bit()) { 543204eeddc0SDimitry Andric StringRef Ref = Res; 543304eeddc0SDimitry Andric auto I = Ref.find("-f80:32-"); 543404eeddc0SDimitry Andric if (I != StringRef::npos) 543504eeddc0SDimitry Andric Res = (Ref.take_front(I) + "-f80:128-" + Ref.drop_front(I + 8)).str(); 543604eeddc0SDimitry Andric } 543704eeddc0SDimitry Andric 543804eeddc0SDimitry Andric return Res; 54398bcb0991SDimitry Andric } 5440480093f4SDimitry Andric 54415ffd83dbSDimitry Andric void llvm::UpgradeAttributes(AttrBuilder &B) { 5442480093f4SDimitry Andric StringRef FramePointer; 544304eeddc0SDimitry Andric Attribute A = B.getAttribute("no-frame-pointer-elim"); 544404eeddc0SDimitry Andric if (A.isValid()) { 5445480093f4SDimitry Andric // The value can be "true" or "false". 544604eeddc0SDimitry Andric FramePointer = A.getValueAsString() == "true" ? "all" : "none"; 5447480093f4SDimitry Andric B.removeAttribute("no-frame-pointer-elim"); 5448480093f4SDimitry Andric } 5449480093f4SDimitry Andric if (B.contains("no-frame-pointer-elim-non-leaf")) { 5450480093f4SDimitry Andric // The value is ignored. "no-frame-pointer-elim"="true" takes priority. 5451480093f4SDimitry Andric if (FramePointer != "all") 5452480093f4SDimitry Andric FramePointer = "non-leaf"; 5453480093f4SDimitry Andric B.removeAttribute("no-frame-pointer-elim-non-leaf"); 5454480093f4SDimitry Andric } 5455480093f4SDimitry Andric if (!FramePointer.empty()) 5456480093f4SDimitry Andric B.addAttribute("frame-pointer", FramePointer); 54575ffd83dbSDimitry Andric 545804eeddc0SDimitry Andric A = B.getAttribute("null-pointer-is-valid"); 545904eeddc0SDimitry Andric if (A.isValid()) { 54605ffd83dbSDimitry Andric // The value can be "true" or "false". 546104eeddc0SDimitry Andric bool NullPointerIsValid = A.getValueAsString() == "true"; 54625ffd83dbSDimitry Andric B.removeAttribute("null-pointer-is-valid"); 54635ffd83dbSDimitry Andric if (NullPointerIsValid) 54645ffd83dbSDimitry Andric B.addAttribute(Attribute::NullPointerIsValid); 54655ffd83dbSDimitry Andric } 5466480093f4SDimitry Andric } 546781ad6265SDimitry Andric 546881ad6265SDimitry Andric void llvm::UpgradeOperandBundles(std::vector<OperandBundleDef> &Bundles) { 546981ad6265SDimitry Andric // clang.arc.attachedcall bundles are now required to have an operand. 547081ad6265SDimitry Andric // If they don't, it's okay to drop them entirely: when there is an operand, 547181ad6265SDimitry Andric // the "attachedcall" is meaningful and required, but without an operand, 547281ad6265SDimitry Andric // it's just a marker NOP. Dropping it merely prevents an optimization. 547381ad6265SDimitry Andric erase_if(Bundles, [&](OperandBundleDef &OBD) { 547481ad6265SDimitry Andric return OBD.getTag() == "clang.arc.attachedcall" && 547581ad6265SDimitry Andric OBD.inputs().empty(); 547681ad6265SDimitry Andric }); 547781ad6265SDimitry Andric } 5478