blob: 4479bccfd45e39652c8f5cff1959fc4820d21053 [file] [log] [blame]
//===-- RISCVLegalizerInfo.cpp ----------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
/// This file implements the targeting of the Machinelegalizer class for RISC-V.
/// \todo This should be generated by TableGen.
//===----------------------------------------------------------------------===//
#include "RISCVLegalizerInfo.h"
#include "RISCVSubtarget.h"
#include "llvm/CodeGen/GlobalISel/LegalizerHelper.h"
#include "llvm/CodeGen/TargetOpcodes.h"
#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Type.h"
using namespace llvm;
RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST) {
const unsigned XLen = ST.getXLen();
const LLT XLenLLT = LLT::scalar(XLen);
const LLT DoubleXLenLLT = LLT::scalar(2 * XLen);
const LLT p0 = LLT::pointer(0, XLen);
const LLT s8 = LLT::scalar(8);
const LLT s16 = LLT::scalar(16);
const LLT s32 = LLT::scalar(32);
using namespace TargetOpcode;
getActionDefinitionsBuilder({G_AND, G_OR, G_XOR})
.legalFor({XLenLLT})
.widenScalarToNextPow2(0)
.clampScalar(0, XLenLLT, XLenLLT);
getActionDefinitionsBuilder({G_ADD, G_SUB})
.legalFor({s32, XLenLLT})
.widenScalarToNextPow2(0)
.clampScalar(0, s32, XLenLLT);
getActionDefinitionsBuilder(
{G_UADDE, G_UADDO, G_USUBE, G_USUBO}).lower();
getActionDefinitionsBuilder({G_SADDO, G_SSUBO}).minScalar(0, XLenLLT).lower();
getActionDefinitionsBuilder({G_ASHR, G_LSHR, G_SHL})
.legalFor({{s32, s32}, {XLenLLT, XLenLLT}})
.widenScalarToNextPow2(0)
.clampScalar(1, s32, XLenLLT)
.clampScalar(0, s32, XLenLLT);
if (ST.is64Bit()) {
getActionDefinitionsBuilder({G_ZEXT, G_SEXT, G_ANYEXT})
.legalFor({{XLenLLT, s32}})
.maxScalar(0, XLenLLT);
getActionDefinitionsBuilder(G_SEXT_INREG)
.customFor({XLenLLT})
.maxScalar(0, XLenLLT)
.lower();
} else {
getActionDefinitionsBuilder({G_ZEXT, G_SEXT, G_ANYEXT})
.maxScalar(0, XLenLLT);
getActionDefinitionsBuilder(G_SEXT_INREG)
.maxScalar(0, XLenLLT)
.lower();
}
// Merge/Unmerge
for (unsigned Op : {G_MERGE_VALUES, G_UNMERGE_VALUES}) {
unsigned BigTyIdx = Op == G_MERGE_VALUES ? 0 : 1;
unsigned LitTyIdx = Op == G_MERGE_VALUES ? 1 : 0;
getActionDefinitionsBuilder(Op)
.widenScalarToNextPow2(LitTyIdx, XLen)
.widenScalarToNextPow2(BigTyIdx, XLen)
.clampScalar(LitTyIdx, XLenLLT, XLenLLT)
.clampScalar(BigTyIdx, XLenLLT, XLenLLT);
}
getActionDefinitionsBuilder({G_CONSTANT, G_IMPLICIT_DEF})
.legalFor({s32, XLenLLT, p0})
.widenScalarToNextPow2(0)
.clampScalar(0, s32, XLenLLT);
getActionDefinitionsBuilder(G_ICMP)
.legalFor({{XLenLLT, XLenLLT}, {XLenLLT, p0}})
.widenScalarToNextPow2(1)
.clampScalar(1, XLenLLT, XLenLLT)
.clampScalar(0, XLenLLT, XLenLLT);
getActionDefinitionsBuilder(G_SELECT)
.legalFor({{XLenLLT, XLenLLT}, {p0, XLenLLT}})
.widenScalarToNextPow2(0)
.clampScalar(0, XLenLLT, XLenLLT)
.clampScalar(1, XLenLLT, XLenLLT);
getActionDefinitionsBuilder({G_LOAD, G_STORE})
.legalForTypesWithMemDesc({{s32, p0, s8, 8},
{s32, p0, s16, 16},
{s32, p0, s32, 32},
{XLenLLT, p0, s8, 8},
{XLenLLT, p0, s16, 16},
{XLenLLT, p0, s32, 32},
{XLenLLT, p0, XLenLLT, XLen},
{p0, p0, XLenLLT, XLen}})
.clampScalar(0, s32, XLenLLT)
.lower();
auto &ZExtLoadActions = getActionDefinitionsBuilder(G_ZEXTLOAD)
.legalForTypesWithMemDesc({{s32, p0, s8, 8},
{s32, p0, s16, 16},
{XLenLLT, p0, s8, 8},
{XLenLLT, p0, s16, 16}});
if (XLen == 64)
ZExtLoadActions.legalForTypesWithMemDesc({{XLenLLT, p0, s32, 32}});
ZExtLoadActions.lower();
getActionDefinitionsBuilder(G_PTR_ADD)
.legalFor({{p0, XLenLLT}});
getActionDefinitionsBuilder(G_BRCOND)
.legalFor({XLenLLT})
.minScalar(0, XLenLLT);
getActionDefinitionsBuilder(G_PHI)
.legalFor({p0, XLenLLT})
.widenScalarToNextPow2(0)
.clampScalar(0, XLenLLT, XLenLLT);
getActionDefinitionsBuilder(G_GLOBAL_VALUE)
.legalFor({p0});
if (ST.hasStdExtM() || ST.hasStdExtZmmul()) {
getActionDefinitionsBuilder(G_MUL)
.legalFor({s32, XLenLLT})
.widenScalarToNextPow2(0)
.clampScalar(0, s32, XLenLLT);
// clang-format off
getActionDefinitionsBuilder({G_SMULH, G_UMULH})
.legalFor({XLenLLT})
.lower();
// clang-format on
} else {
getActionDefinitionsBuilder(G_MUL)
.libcallFor({XLenLLT, DoubleXLenLLT})
.widenScalarToNextPow2(0)
.clampScalar(0, XLenLLT, DoubleXLenLLT);
getActionDefinitionsBuilder({G_SMULH, G_UMULH}).lowerFor({XLenLLT});
}
if (ST.hasStdExtM()) {
getActionDefinitionsBuilder({G_UDIV, G_SDIV, G_UREM, G_SREM})
.legalFor({s32, XLenLLT})
.libcallFor({DoubleXLenLLT})
.clampScalar(0, s32, DoubleXLenLLT)
.widenScalarToNextPow2(0);
} else {
getActionDefinitionsBuilder({G_UDIV, G_SDIV, G_UREM, G_SREM})
.libcallFor({XLenLLT, DoubleXLenLLT})
.clampScalar(0, XLenLLT, DoubleXLenLLT)
.widenScalarToNextPow2(0);
}
getActionDefinitionsBuilder(G_ABS).lower();
getActionDefinitionsBuilder(G_FRAME_INDEX).legalFor({p0});
getLegacyLegalizerInfo().computeTables();
}
bool RISCVLegalizerInfo::legalizeCustom(LegalizerHelper &Helper,
MachineInstr &MI) const {
switch (MI.getOpcode()) {
default:
// No idea what to do.
return false;
case TargetOpcode::G_SEXT_INREG: {
// Source size of 32 is sext.w.
int64_t SizeInBits = MI.getOperand(2).getImm();
if (SizeInBits == 32)
return true;
return Helper.lower(MI, 0, /* Unused hint type */ LLT()) ==
LegalizerHelper::Legalized;
}
}
llvm_unreachable("expected switch to return");
}