
These are identified by misc-include-cleaner. I've filtered out those that break builds. Also, I'm staying away from llvm-config.h, config.h, and Compiler.h, which likely cause platform- or compiler-specific build failures.
288 lines
10 KiB
C++
288 lines
10 KiB
C++
//===-- SPIRVInstrInfo.cpp - SPIR-V Instruction Information ------*- 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file contains the SPIR-V implementation of the TargetInstrInfo class.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "SPIRVInstrInfo.h"
|
|
#include "SPIRV.h"
|
|
#include "llvm/ADT/SmallVector.h"
|
|
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
|
|
#include "llvm/CodeGen/MachineBasicBlock.h"
|
|
#include "llvm/IR/DebugLoc.h"
|
|
|
|
#define GET_INSTRINFO_CTOR_DTOR
|
|
#include "SPIRVGenInstrInfo.inc"
|
|
|
|
using namespace llvm;
|
|
|
|
SPIRVInstrInfo::SPIRVInstrInfo() : SPIRVGenInstrInfo() {}
|
|
|
|
bool SPIRVInstrInfo::isConstantInstr(const MachineInstr &MI) const {
|
|
switch (MI.getOpcode()) {
|
|
case SPIRV::OpConstantTrue:
|
|
case SPIRV::OpConstantFalse:
|
|
case SPIRV::OpConstantI:
|
|
case SPIRV::OpConstantF:
|
|
case SPIRV::OpConstantComposite:
|
|
case SPIRV::OpConstantCompositeContinuedINTEL:
|
|
case SPIRV::OpConstantSampler:
|
|
case SPIRV::OpConstantNull:
|
|
case SPIRV::OpSpecConstantTrue:
|
|
case SPIRV::OpSpecConstantFalse:
|
|
case SPIRV::OpSpecConstant:
|
|
case SPIRV::OpSpecConstantComposite:
|
|
case SPIRV::OpSpecConstantCompositeContinuedINTEL:
|
|
case SPIRV::OpSpecConstantOp:
|
|
case SPIRV::OpUndef:
|
|
case SPIRV::OpConstantFunctionPointerINTEL:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool SPIRVInstrInfo::isSpecConstantInstr(const MachineInstr &MI) const {
|
|
switch (MI.getOpcode()) {
|
|
case SPIRV::OpSpecConstantTrue:
|
|
case SPIRV::OpSpecConstantFalse:
|
|
case SPIRV::OpSpecConstant:
|
|
case SPIRV::OpSpecConstantComposite:
|
|
case SPIRV::OpSpecConstantCompositeContinuedINTEL:
|
|
case SPIRV::OpSpecConstantOp:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool SPIRVInstrInfo::isInlineAsmDefInstr(const MachineInstr &MI) const {
|
|
switch (MI.getOpcode()) {
|
|
case SPIRV::OpAsmTargetINTEL:
|
|
case SPIRV::OpAsmINTEL:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool SPIRVInstrInfo::isTypeDeclInstr(const MachineInstr &MI) const {
|
|
auto &MRI = MI.getMF()->getRegInfo();
|
|
if (MI.getNumDefs() >= 1 && MI.getOperand(0).isReg()) {
|
|
auto DefRegClass = MRI.getRegClassOrNull(MI.getOperand(0).getReg());
|
|
return DefRegClass && DefRegClass->getID() == SPIRV::TYPERegClass.getID();
|
|
} else {
|
|
return MI.getOpcode() == SPIRV::OpTypeForwardPointer ||
|
|
MI.getOpcode() == SPIRV::OpTypeStructContinuedINTEL;
|
|
}
|
|
}
|
|
|
|
bool SPIRVInstrInfo::isDecorationInstr(const MachineInstr &MI) const {
|
|
switch (MI.getOpcode()) {
|
|
case SPIRV::OpDecorate:
|
|
case SPIRV::OpDecorateId:
|
|
case SPIRV::OpDecorateString:
|
|
case SPIRV::OpMemberDecorate:
|
|
case SPIRV::OpMemberDecorateString:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool SPIRVInstrInfo::isAliasingInstr(const MachineInstr &MI) const {
|
|
switch (MI.getOpcode()) {
|
|
case SPIRV::OpAliasDomainDeclINTEL:
|
|
case SPIRV::OpAliasScopeDeclINTEL:
|
|
case SPIRV::OpAliasScopeListDeclINTEL:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool SPIRVInstrInfo::isHeaderInstr(const MachineInstr &MI) const {
|
|
switch (MI.getOpcode()) {
|
|
case SPIRV::OpCapability:
|
|
case SPIRV::OpExtension:
|
|
case SPIRV::OpExtInstImport:
|
|
case SPIRV::OpMemoryModel:
|
|
case SPIRV::OpEntryPoint:
|
|
case SPIRV::OpExecutionMode:
|
|
case SPIRV::OpExecutionModeId:
|
|
case SPIRV::OpString:
|
|
case SPIRV::OpSourceExtension:
|
|
case SPIRV::OpSource:
|
|
case SPIRV::OpSourceContinued:
|
|
case SPIRV::OpName:
|
|
case SPIRV::OpMemberName:
|
|
case SPIRV::OpModuleProcessed:
|
|
return true;
|
|
default:
|
|
return isTypeDeclInstr(MI) || isConstantInstr(MI) ||
|
|
isDecorationInstr(MI) || isAliasingInstr(MI);
|
|
}
|
|
}
|
|
|
|
bool SPIRVInstrInfo::canUseFastMathFlags(const MachineInstr &MI) const {
|
|
switch (MI.getOpcode()) {
|
|
case SPIRV::OpFAddS:
|
|
case SPIRV::OpFSubS:
|
|
case SPIRV::OpFMulS:
|
|
case SPIRV::OpFDivS:
|
|
case SPIRV::OpFRemS:
|
|
case SPIRV::OpFAddV:
|
|
case SPIRV::OpFSubV:
|
|
case SPIRV::OpFMulV:
|
|
case SPIRV::OpFDivV:
|
|
case SPIRV::OpFRemV:
|
|
case SPIRV::OpFMod:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool SPIRVInstrInfo::canUseNSW(const MachineInstr &MI) const {
|
|
switch (MI.getOpcode()) {
|
|
case SPIRV::OpIAddS:
|
|
case SPIRV::OpIAddV:
|
|
case SPIRV::OpISubS:
|
|
case SPIRV::OpISubV:
|
|
case SPIRV::OpIMulS:
|
|
case SPIRV::OpIMulV:
|
|
case SPIRV::OpShiftLeftLogicalS:
|
|
case SPIRV::OpShiftLeftLogicalV:
|
|
case SPIRV::OpSNegate:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool SPIRVInstrInfo::canUseNUW(const MachineInstr &MI) const {
|
|
switch (MI.getOpcode()) {
|
|
case SPIRV::OpIAddS:
|
|
case SPIRV::OpIAddV:
|
|
case SPIRV::OpISubS:
|
|
case SPIRV::OpISubV:
|
|
case SPIRV::OpIMulS:
|
|
case SPIRV::OpIMulV:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Analyze the branching code at the end of MBB, returning
|
|
// true if it cannot be understood (e.g. it's a switch dispatch or isn't
|
|
// implemented for a target). Upon success, this returns false and returns
|
|
// with the following information in various cases:
|
|
//
|
|
// 1. If this block ends with no branches (it just falls through to its succ)
|
|
// just return false, leaving TBB/FBB null.
|
|
// 2. If this block ends with only an unconditional branch, it sets TBB to be
|
|
// the destination block.
|
|
// 3. If this block ends with a conditional branch and it falls through to a
|
|
// successor block, it sets TBB to be the branch destination block and a
|
|
// list of operands that evaluate the condition. These operands can be
|
|
// passed to other TargetInstrInfo methods to create new branches.
|
|
// 4. If this block ends with a conditional branch followed by an
|
|
// unconditional branch, it returns the 'true' destination in TBB, the
|
|
// 'false' destination in FBB, and a list of operands that evaluate the
|
|
// condition. These operands can be passed to other TargetInstrInfo
|
|
// methods to create new branches.
|
|
//
|
|
// Note that removeBranch and insertBranch must be implemented to support
|
|
// cases where this method returns success.
|
|
//
|
|
// If AllowModify is true, then this routine is allowed to modify the basic
|
|
// block (e.g. delete instructions after the unconditional branch).
|
|
//
|
|
// The CFG information in MBB.Predecessors and MBB.Successors must be valid
|
|
// before calling this function.
|
|
bool SPIRVInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
|
|
MachineBasicBlock *&TBB,
|
|
MachineBasicBlock *&FBB,
|
|
SmallVectorImpl<MachineOperand> &Cond,
|
|
bool AllowModify) const {
|
|
// We do not allow to restructure blocks by results of analyzeBranch(),
|
|
// because it may potentially break structured control flow and anyway
|
|
// doubtedly may be useful in SPIRV, including such reasons as, e.g.:
|
|
// 1) there is no way to encode `if (Cond) then Stmt` logic, only full
|
|
// if-then-else is supported by OpBranchConditional, so if we supported
|
|
// splitting of blocks ending with OpBranchConditional MachineBasicBlock.cpp
|
|
// would expect successfull implementation of calls to insertBranch() setting
|
|
// FBB to null that is not feasible; 2) it's not possible to delete
|
|
// instructions after the unconditional branch, because this instruction must
|
|
// be the last instruction in a block.
|
|
return true;
|
|
}
|
|
|
|
// Remove the branching code at the end of the specific MBB.
|
|
// This is only invoked in cases where analyzeBranch returns success. It
|
|
// returns the number of instructions that were removed.
|
|
// If \p BytesRemoved is non-null, report the change in code size from the
|
|
// removed instructions.
|
|
unsigned SPIRVInstrInfo::removeBranch(MachineBasicBlock &MBB,
|
|
int * /*BytesRemoved*/) const {
|
|
MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();
|
|
if (I == MBB.end())
|
|
return 0;
|
|
|
|
if (I->getOpcode() == SPIRV::OpBranch) {
|
|
I->eraseFromParent();
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Insert branch code into the end of the specified MachineBasicBlock. The
|
|
// operands to this method are the same as those returned by analyzeBranch.
|
|
// This is only invoked in cases where analyzeBranch returns success. It
|
|
// returns the number of instructions inserted. If \p BytesAdded is non-null,
|
|
// report the change in code size from the added instructions.
|
|
//
|
|
// It is also invoked by tail merging to add unconditional branches in
|
|
// cases where analyzeBranch doesn't apply because there was no original
|
|
// branch to analyze. At least this much must be implemented, else tail
|
|
// merging needs to be disabled.
|
|
//
|
|
// The CFG information in MBB.Predecessors and MBB.Successors must be valid
|
|
// before calling this function.
|
|
unsigned SPIRVInstrInfo::insertBranch(MachineBasicBlock &MBB,
|
|
MachineBasicBlock *TBB,
|
|
MachineBasicBlock *FBB,
|
|
ArrayRef<MachineOperand> Cond,
|
|
const DebugLoc &DL,
|
|
int * /*BytesAdded*/) const {
|
|
if (!TBB)
|
|
return 0;
|
|
BuildMI(&MBB, DL, get(SPIRV::OpBranch)).addMBB(TBB);
|
|
return 1;
|
|
}
|
|
|
|
void SPIRVInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
|
|
MachineBasicBlock::iterator I,
|
|
const DebugLoc &DL, Register DestReg,
|
|
Register SrcReg, bool KillSrc,
|
|
bool RenamableDest, bool RenamableSrc) const {
|
|
// Actually we don't need this COPY instruction. However if we do nothing with
|
|
// it, post RA pseudo instrs expansion just removes it and we get the code
|
|
// with undef registers. Therefore, we need to replace all uses of dst with
|
|
// the src register. COPY instr itself will be safely removed later.
|
|
assert(I->isCopy() && "Copy instruction is expected");
|
|
auto DstOp = I->getOperand(0);
|
|
auto SrcOp = I->getOperand(1);
|
|
assert(DstOp.isReg() && SrcOp.isReg() &&
|
|
"Register operands are expected in COPY");
|
|
auto &MRI = I->getMF()->getRegInfo();
|
|
MRI.replaceRegWith(DstOp.getReg(), SrcOp.getReg());
|
|
}
|