Path: blob/main/contrib/llvm-project/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp
35269 views
//===- ARMLegalizerInfo.cpp --------------------------------------*- C++ -*-==//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7/// \file8/// This file implements the targeting of the Machinelegalizer class for ARM.9/// \todo This should be generated by TableGen.10//===----------------------------------------------------------------------===//1112#include "ARMLegalizerInfo.h"13#include "ARMCallLowering.h"14#include "ARMSubtarget.h"15#include "llvm/CodeGen/GlobalISel/LegalizerHelper.h"16#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"17#include "llvm/CodeGen/LowLevelTypeUtils.h"18#include "llvm/CodeGen/MachineRegisterInfo.h"19#include "llvm/CodeGen/TargetOpcodes.h"20#include "llvm/CodeGen/ValueTypes.h"21#include "llvm/IR/DerivedTypes.h"22#include "llvm/IR/Type.h"2324using namespace llvm;25using namespace LegalizeActions;2627static bool AEABI(const ARMSubtarget &ST) {28return ST.isTargetAEABI() || ST.isTargetGNUAEABI() || ST.isTargetMuslAEABI();29}3031ARMLegalizerInfo::ARMLegalizerInfo(const ARMSubtarget &ST) {32using namespace TargetOpcode;3334const LLT p0 = LLT::pointer(0, 32);3536const LLT s1 = LLT::scalar(1);37const LLT s8 = LLT::scalar(8);38const LLT s16 = LLT::scalar(16);39const LLT s32 = LLT::scalar(32);40const LLT s64 = LLT::scalar(64);4142auto &LegacyInfo = getLegacyLegalizerInfo();43if (ST.isThumb1Only()) {44// Thumb1 is not supported yet.45LegacyInfo.computeTables();46verify(*ST.getInstrInfo());47return;48}4950getActionDefinitionsBuilder({G_SEXT, G_ZEXT, G_ANYEXT})51.legalForCartesianProduct({s8, s16, s32}, {s1, s8, s16});5253getActionDefinitionsBuilder(G_SEXT_INREG).lower();5455getActionDefinitionsBuilder({G_MUL, G_AND, G_OR, G_XOR})56.legalFor({s32})57.clampScalar(0, s32, s32);5859if (ST.hasNEON())60getActionDefinitionsBuilder({G_ADD, G_SUB})61.legalFor({s32, s64})62.minScalar(0, s32);63else64getActionDefinitionsBuilder({G_ADD, G_SUB})65.legalFor({s32})66.minScalar(0, s32);6768getActionDefinitionsBuilder({G_ASHR, G_LSHR, G_SHL})69.legalFor({{s32, s32}})70.minScalar(0, s32)71.clampScalar(1, s32, s32);7273bool HasHWDivide = (!ST.isThumb() && ST.hasDivideInARMMode()) ||74(ST.isThumb() && ST.hasDivideInThumbMode());75if (HasHWDivide)76getActionDefinitionsBuilder({G_SDIV, G_UDIV})77.legalFor({s32})78.clampScalar(0, s32, s32);79else80getActionDefinitionsBuilder({G_SDIV, G_UDIV})81.libcallFor({s32})82.clampScalar(0, s32, s32);8384auto &REMBuilder =85getActionDefinitionsBuilder({G_SREM, G_UREM}).minScalar(0, s32);86if (HasHWDivide)87REMBuilder.lowerFor({s32});88else if (AEABI(ST))89REMBuilder.customFor({s32});90else91REMBuilder.libcallFor({s32});9293getActionDefinitionsBuilder(G_INTTOPTR)94.legalFor({{p0, s32}})95.minScalar(1, s32);96getActionDefinitionsBuilder(G_PTRTOINT)97.legalFor({{s32, p0}})98.minScalar(0, s32);99100getActionDefinitionsBuilder(G_CONSTANT)101.legalFor({s32, p0})102.clampScalar(0, s32, s32);103104getActionDefinitionsBuilder(G_ICMP)105.legalForCartesianProduct({s1}, {s32, p0})106.minScalar(1, s32);107108getActionDefinitionsBuilder(G_SELECT)109.legalForCartesianProduct({s32, p0}, {s1})110.minScalar(0, s32);111112// We're keeping these builders around because we'll want to add support for113// floating point to them.114auto &LoadStoreBuilder = getActionDefinitionsBuilder({G_LOAD, G_STORE})115.legalForTypesWithMemDesc({{s8, p0, s8, 8},116{s16, p0, s16, 8},117{s32, p0, s32, 8},118{p0, p0, p0, 8}})119.unsupportedIfMemSizeNotPow2();120121getActionDefinitionsBuilder(G_FRAME_INDEX).legalFor({p0});122getActionDefinitionsBuilder(G_GLOBAL_VALUE).legalFor({p0});123124auto &PhiBuilder =125getActionDefinitionsBuilder(G_PHI)126.legalFor({s32, p0})127.minScalar(0, s32);128129getActionDefinitionsBuilder(G_PTR_ADD)130.legalFor({{p0, s32}})131.minScalar(1, s32);132133getActionDefinitionsBuilder(G_BRCOND).legalFor({s1});134135if (!ST.useSoftFloat() && ST.hasVFP2Base()) {136getActionDefinitionsBuilder(137{G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FCONSTANT, G_FNEG})138.legalFor({s32, s64});139140LoadStoreBuilder141.legalForTypesWithMemDesc({{s64, p0, s64, 32}})142.maxScalar(0, s32);143PhiBuilder.legalFor({s64});144145getActionDefinitionsBuilder(G_FCMP).legalForCartesianProduct({s1},146{s32, s64});147148getActionDefinitionsBuilder(G_MERGE_VALUES).legalFor({{s64, s32}});149getActionDefinitionsBuilder(G_UNMERGE_VALUES).legalFor({{s32, s64}});150151getActionDefinitionsBuilder(G_FPEXT).legalFor({{s64, s32}});152getActionDefinitionsBuilder(G_FPTRUNC).legalFor({{s32, s64}});153154getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI})155.legalForCartesianProduct({s32}, {s32, s64});156getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})157.legalForCartesianProduct({s32, s64}, {s32});158159getActionDefinitionsBuilder({G_GET_FPENV, G_SET_FPENV, G_GET_FPMODE})160.legalFor({s32});161getActionDefinitionsBuilder(G_RESET_FPENV).alwaysLegal();162getActionDefinitionsBuilder(G_SET_FPMODE).customFor({s32});163} else {164getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV})165.libcallFor({s32, s64});166167LoadStoreBuilder.maxScalar(0, s32);168169getActionDefinitionsBuilder(G_FNEG).lowerFor({s32, s64});170171getActionDefinitionsBuilder(G_FCONSTANT).customFor({s32, s64});172173getActionDefinitionsBuilder(G_FCMP).customForCartesianProduct({s1},174{s32, s64});175176if (AEABI(ST))177setFCmpLibcallsAEABI();178else179setFCmpLibcallsGNU();180181getActionDefinitionsBuilder(G_FPEXT).libcallFor({{s64, s32}});182getActionDefinitionsBuilder(G_FPTRUNC).libcallFor({{s32, s64}});183184getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI})185.libcallForCartesianProduct({s32}, {s32, s64});186getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})187.libcallForCartesianProduct({s32, s64}, {s32});188189getActionDefinitionsBuilder({G_GET_FPENV, G_SET_FPENV, G_RESET_FPENV})190.libcall();191getActionDefinitionsBuilder({G_GET_FPMODE, G_SET_FPMODE, G_RESET_FPMODE})192.libcall();193}194195// Just expand whatever loads and stores are left.196LoadStoreBuilder.lower();197198if (!ST.useSoftFloat() && ST.hasVFP4Base())199getActionDefinitionsBuilder(G_FMA).legalFor({s32, s64});200else201getActionDefinitionsBuilder(G_FMA).libcallFor({s32, s64});202203getActionDefinitionsBuilder({G_FREM, G_FPOW}).libcallFor({s32, s64});204205if (ST.hasV5TOps()) {206getActionDefinitionsBuilder(G_CTLZ)207.legalFor({s32, s32})208.clampScalar(1, s32, s32)209.clampScalar(0, s32, s32);210getActionDefinitionsBuilder(G_CTLZ_ZERO_UNDEF)211.lowerFor({s32, s32})212.clampScalar(1, s32, s32)213.clampScalar(0, s32, s32);214} else {215getActionDefinitionsBuilder(G_CTLZ_ZERO_UNDEF)216.libcallFor({s32, s32})217.clampScalar(1, s32, s32)218.clampScalar(0, s32, s32);219getActionDefinitionsBuilder(G_CTLZ)220.lowerFor({s32, s32})221.clampScalar(1, s32, s32)222.clampScalar(0, s32, s32);223}224225LegacyInfo.computeTables();226verify(*ST.getInstrInfo());227}228229void ARMLegalizerInfo::setFCmpLibcallsAEABI() {230// FCMP_TRUE and FCMP_FALSE don't need libcalls, they should be231// default-initialized.232FCmp32Libcalls.resize(CmpInst::LAST_FCMP_PREDICATE + 1);233FCmp32Libcalls[CmpInst::FCMP_OEQ] = {234{RTLIB::OEQ_F32, CmpInst::BAD_ICMP_PREDICATE}};235FCmp32Libcalls[CmpInst::FCMP_OGE] = {236{RTLIB::OGE_F32, CmpInst::BAD_ICMP_PREDICATE}};237FCmp32Libcalls[CmpInst::FCMP_OGT] = {238{RTLIB::OGT_F32, CmpInst::BAD_ICMP_PREDICATE}};239FCmp32Libcalls[CmpInst::FCMP_OLE] = {240{RTLIB::OLE_F32, CmpInst::BAD_ICMP_PREDICATE}};241FCmp32Libcalls[CmpInst::FCMP_OLT] = {242{RTLIB::OLT_F32, CmpInst::BAD_ICMP_PREDICATE}};243FCmp32Libcalls[CmpInst::FCMP_ORD] = {{RTLIB::UO_F32, CmpInst::ICMP_EQ}};244FCmp32Libcalls[CmpInst::FCMP_UGE] = {{RTLIB::OLT_F32, CmpInst::ICMP_EQ}};245FCmp32Libcalls[CmpInst::FCMP_UGT] = {{RTLIB::OLE_F32, CmpInst::ICMP_EQ}};246FCmp32Libcalls[CmpInst::FCMP_ULE] = {{RTLIB::OGT_F32, CmpInst::ICMP_EQ}};247FCmp32Libcalls[CmpInst::FCMP_ULT] = {{RTLIB::OGE_F32, CmpInst::ICMP_EQ}};248FCmp32Libcalls[CmpInst::FCMP_UNE] = {{RTLIB::UNE_F32, CmpInst::ICMP_EQ}};249FCmp32Libcalls[CmpInst::FCMP_UNO] = {250{RTLIB::UO_F32, CmpInst::BAD_ICMP_PREDICATE}};251FCmp32Libcalls[CmpInst::FCMP_ONE] = {252{RTLIB::OGT_F32, CmpInst::BAD_ICMP_PREDICATE},253{RTLIB::OLT_F32, CmpInst::BAD_ICMP_PREDICATE}};254FCmp32Libcalls[CmpInst::FCMP_UEQ] = {255{RTLIB::OEQ_F32, CmpInst::BAD_ICMP_PREDICATE},256{RTLIB::UO_F32, CmpInst::BAD_ICMP_PREDICATE}};257258FCmp64Libcalls.resize(CmpInst::LAST_FCMP_PREDICATE + 1);259FCmp64Libcalls[CmpInst::FCMP_OEQ] = {260{RTLIB::OEQ_F64, CmpInst::BAD_ICMP_PREDICATE}};261FCmp64Libcalls[CmpInst::FCMP_OGE] = {262{RTLIB::OGE_F64, CmpInst::BAD_ICMP_PREDICATE}};263FCmp64Libcalls[CmpInst::FCMP_OGT] = {264{RTLIB::OGT_F64, CmpInst::BAD_ICMP_PREDICATE}};265FCmp64Libcalls[CmpInst::FCMP_OLE] = {266{RTLIB::OLE_F64, CmpInst::BAD_ICMP_PREDICATE}};267FCmp64Libcalls[CmpInst::FCMP_OLT] = {268{RTLIB::OLT_F64, CmpInst::BAD_ICMP_PREDICATE}};269FCmp64Libcalls[CmpInst::FCMP_ORD] = {{RTLIB::UO_F64, CmpInst::ICMP_EQ}};270FCmp64Libcalls[CmpInst::FCMP_UGE] = {{RTLIB::OLT_F64, CmpInst::ICMP_EQ}};271FCmp64Libcalls[CmpInst::FCMP_UGT] = {{RTLIB::OLE_F64, CmpInst::ICMP_EQ}};272FCmp64Libcalls[CmpInst::FCMP_ULE] = {{RTLIB::OGT_F64, CmpInst::ICMP_EQ}};273FCmp64Libcalls[CmpInst::FCMP_ULT] = {{RTLIB::OGE_F64, CmpInst::ICMP_EQ}};274FCmp64Libcalls[CmpInst::FCMP_UNE] = {{RTLIB::UNE_F64, CmpInst::ICMP_EQ}};275FCmp64Libcalls[CmpInst::FCMP_UNO] = {276{RTLIB::UO_F64, CmpInst::BAD_ICMP_PREDICATE}};277FCmp64Libcalls[CmpInst::FCMP_ONE] = {278{RTLIB::OGT_F64, CmpInst::BAD_ICMP_PREDICATE},279{RTLIB::OLT_F64, CmpInst::BAD_ICMP_PREDICATE}};280FCmp64Libcalls[CmpInst::FCMP_UEQ] = {281{RTLIB::OEQ_F64, CmpInst::BAD_ICMP_PREDICATE},282{RTLIB::UO_F64, CmpInst::BAD_ICMP_PREDICATE}};283}284285void ARMLegalizerInfo::setFCmpLibcallsGNU() {286// FCMP_TRUE and FCMP_FALSE don't need libcalls, they should be287// default-initialized.288FCmp32Libcalls.resize(CmpInst::LAST_FCMP_PREDICATE + 1);289FCmp32Libcalls[CmpInst::FCMP_OEQ] = {{RTLIB::OEQ_F32, CmpInst::ICMP_EQ}};290FCmp32Libcalls[CmpInst::FCMP_OGE] = {{RTLIB::OGE_F32, CmpInst::ICMP_SGE}};291FCmp32Libcalls[CmpInst::FCMP_OGT] = {{RTLIB::OGT_F32, CmpInst::ICMP_SGT}};292FCmp32Libcalls[CmpInst::FCMP_OLE] = {{RTLIB::OLE_F32, CmpInst::ICMP_SLE}};293FCmp32Libcalls[CmpInst::FCMP_OLT] = {{RTLIB::OLT_F32, CmpInst::ICMP_SLT}};294FCmp32Libcalls[CmpInst::FCMP_ORD] = {{RTLIB::UO_F32, CmpInst::ICMP_EQ}};295FCmp32Libcalls[CmpInst::FCMP_UGE] = {{RTLIB::OLT_F32, CmpInst::ICMP_SGE}};296FCmp32Libcalls[CmpInst::FCMP_UGT] = {{RTLIB::OLE_F32, CmpInst::ICMP_SGT}};297FCmp32Libcalls[CmpInst::FCMP_ULE] = {{RTLIB::OGT_F32, CmpInst::ICMP_SLE}};298FCmp32Libcalls[CmpInst::FCMP_ULT] = {{RTLIB::OGE_F32, CmpInst::ICMP_SLT}};299FCmp32Libcalls[CmpInst::FCMP_UNE] = {{RTLIB::UNE_F32, CmpInst::ICMP_NE}};300FCmp32Libcalls[CmpInst::FCMP_UNO] = {{RTLIB::UO_F32, CmpInst::ICMP_NE}};301FCmp32Libcalls[CmpInst::FCMP_ONE] = {{RTLIB::OGT_F32, CmpInst::ICMP_SGT},302{RTLIB::OLT_F32, CmpInst::ICMP_SLT}};303FCmp32Libcalls[CmpInst::FCMP_UEQ] = {{RTLIB::OEQ_F32, CmpInst::ICMP_EQ},304{RTLIB::UO_F32, CmpInst::ICMP_NE}};305306FCmp64Libcalls.resize(CmpInst::LAST_FCMP_PREDICATE + 1);307FCmp64Libcalls[CmpInst::FCMP_OEQ] = {{RTLIB::OEQ_F64, CmpInst::ICMP_EQ}};308FCmp64Libcalls[CmpInst::FCMP_OGE] = {{RTLIB::OGE_F64, CmpInst::ICMP_SGE}};309FCmp64Libcalls[CmpInst::FCMP_OGT] = {{RTLIB::OGT_F64, CmpInst::ICMP_SGT}};310FCmp64Libcalls[CmpInst::FCMP_OLE] = {{RTLIB::OLE_F64, CmpInst::ICMP_SLE}};311FCmp64Libcalls[CmpInst::FCMP_OLT] = {{RTLIB::OLT_F64, CmpInst::ICMP_SLT}};312FCmp64Libcalls[CmpInst::FCMP_ORD] = {{RTLIB::UO_F64, CmpInst::ICMP_EQ}};313FCmp64Libcalls[CmpInst::FCMP_UGE] = {{RTLIB::OLT_F64, CmpInst::ICMP_SGE}};314FCmp64Libcalls[CmpInst::FCMP_UGT] = {{RTLIB::OLE_F64, CmpInst::ICMP_SGT}};315FCmp64Libcalls[CmpInst::FCMP_ULE] = {{RTLIB::OGT_F64, CmpInst::ICMP_SLE}};316FCmp64Libcalls[CmpInst::FCMP_ULT] = {{RTLIB::OGE_F64, CmpInst::ICMP_SLT}};317FCmp64Libcalls[CmpInst::FCMP_UNE] = {{RTLIB::UNE_F64, CmpInst::ICMP_NE}};318FCmp64Libcalls[CmpInst::FCMP_UNO] = {{RTLIB::UO_F64, CmpInst::ICMP_NE}};319FCmp64Libcalls[CmpInst::FCMP_ONE] = {{RTLIB::OGT_F64, CmpInst::ICMP_SGT},320{RTLIB::OLT_F64, CmpInst::ICMP_SLT}};321FCmp64Libcalls[CmpInst::FCMP_UEQ] = {{RTLIB::OEQ_F64, CmpInst::ICMP_EQ},322{RTLIB::UO_F64, CmpInst::ICMP_NE}};323}324325ARMLegalizerInfo::FCmpLibcallsList326ARMLegalizerInfo::getFCmpLibcalls(CmpInst::Predicate Predicate,327unsigned Size) const {328assert(CmpInst::isFPPredicate(Predicate) && "Unsupported FCmp predicate");329if (Size == 32)330return FCmp32Libcalls[Predicate];331if (Size == 64)332return FCmp64Libcalls[Predicate];333llvm_unreachable("Unsupported size for FCmp predicate");334}335336bool ARMLegalizerInfo::legalizeCustom(LegalizerHelper &Helper, MachineInstr &MI,337LostDebugLocObserver &LocObserver) const {338using namespace TargetOpcode;339340MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;341MachineRegisterInfo &MRI = *MIRBuilder.getMRI();342LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext();343344switch (MI.getOpcode()) {345default:346return false;347case G_SREM:348case G_UREM: {349Register OriginalResult = MI.getOperand(0).getReg();350auto Size = MRI.getType(OriginalResult).getSizeInBits();351if (Size != 32)352return false;353354auto Libcall =355MI.getOpcode() == G_SREM ? RTLIB::SDIVREM_I32 : RTLIB::UDIVREM_I32;356357// Our divmod libcalls return a struct containing the quotient and the358// remainder. Create a new, unused register for the quotient and use the359// destination of the original instruction for the remainder.360Type *ArgTy = Type::getInt32Ty(Ctx);361StructType *RetTy = StructType::get(Ctx, {ArgTy, ArgTy}, /* Packed */ true);362Register RetRegs[] = {MRI.createGenericVirtualRegister(LLT::scalar(32)),363OriginalResult};364auto Status = createLibcall(MIRBuilder, Libcall, {RetRegs, RetTy, 0},365{{MI.getOperand(1).getReg(), ArgTy, 0},366{MI.getOperand(2).getReg(), ArgTy, 0}},367LocObserver, &MI);368if (Status != LegalizerHelper::Legalized)369return false;370break;371}372case G_FCMP: {373assert(MRI.getType(MI.getOperand(2).getReg()) ==374MRI.getType(MI.getOperand(3).getReg()) &&375"Mismatched operands for G_FCMP");376auto OpSize = MRI.getType(MI.getOperand(2).getReg()).getSizeInBits();377378auto OriginalResult = MI.getOperand(0).getReg();379auto Predicate =380static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());381auto Libcalls = getFCmpLibcalls(Predicate, OpSize);382383if (Libcalls.empty()) {384assert((Predicate == CmpInst::FCMP_TRUE ||385Predicate == CmpInst::FCMP_FALSE) &&386"Predicate needs libcalls, but none specified");387MIRBuilder.buildConstant(OriginalResult,388Predicate == CmpInst::FCMP_TRUE ? 1 : 0);389MI.eraseFromParent();390return true;391}392393assert((OpSize == 32 || OpSize == 64) && "Unsupported operand size");394auto *ArgTy = OpSize == 32 ? Type::getFloatTy(Ctx) : Type::getDoubleTy(Ctx);395auto *RetTy = Type::getInt32Ty(Ctx);396397SmallVector<Register, 2> Results;398for (auto Libcall : Libcalls) {399auto LibcallResult = MRI.createGenericVirtualRegister(LLT::scalar(32));400auto Status = createLibcall(MIRBuilder, Libcall.LibcallID,401{LibcallResult, RetTy, 0},402{{MI.getOperand(2).getReg(), ArgTy, 0},403{MI.getOperand(3).getReg(), ArgTy, 0}},404LocObserver, &MI);405406if (Status != LegalizerHelper::Legalized)407return false;408409auto ProcessedResult =410Libcalls.size() == 1411? OriginalResult412: MRI.createGenericVirtualRegister(MRI.getType(OriginalResult));413414// We have a result, but we need to transform it into a proper 1-bit 0 or415// 1, taking into account the different peculiarities of the values416// returned by the comparison functions.417CmpInst::Predicate ResultPred = Libcall.Predicate;418if (ResultPred == CmpInst::BAD_ICMP_PREDICATE) {419// We have a nice 0 or 1, and we just need to truncate it back to 1 bit420// to keep the types consistent.421MIRBuilder.buildTrunc(ProcessedResult, LibcallResult);422} else {423// We need to compare against 0.424assert(CmpInst::isIntPredicate(ResultPred) && "Unsupported predicate");425auto Zero = MIRBuilder.buildConstant(LLT::scalar(32), 0);426MIRBuilder.buildICmp(ResultPred, ProcessedResult, LibcallResult, Zero);427}428Results.push_back(ProcessedResult);429}430431if (Results.size() != 1) {432assert(Results.size() == 2 && "Unexpected number of results");433MIRBuilder.buildOr(OriginalResult, Results[0], Results[1]);434}435break;436}437case G_FCONSTANT: {438// Convert to integer constants, while preserving the binary representation.439auto AsInteger =440MI.getOperand(1).getFPImm()->getValueAPF().bitcastToAPInt();441MIRBuilder.buildConstant(MI.getOperand(0),442*ConstantInt::get(Ctx, AsInteger));443break;444}445case G_SET_FPMODE: {446// New FPSCR = (FPSCR & FPStatusBits) | (Modes & ~FPStatusBits)447LLT FPEnvTy = LLT::scalar(32);448auto FPEnv = MRI.createGenericVirtualRegister(FPEnvTy);449Register Modes = MI.getOperand(0).getReg();450MIRBuilder.buildGetFPEnv(FPEnv);451auto StatusBitMask = MIRBuilder.buildConstant(FPEnvTy, ARM::FPStatusBits);452auto StatusBits = MIRBuilder.buildAnd(FPEnvTy, FPEnv, StatusBitMask);453auto NotStatusBitMask =454MIRBuilder.buildConstant(FPEnvTy, ~ARM::FPStatusBits);455auto FPModeBits = MIRBuilder.buildAnd(FPEnvTy, Modes, NotStatusBitMask);456auto NewFPSCR = MIRBuilder.buildOr(FPEnvTy, StatusBits, FPModeBits);457MIRBuilder.buildSetFPEnv(NewFPSCR);458break;459}460}461462MI.eraseFromParent();463return true;464}465466467