R600/SI: cleanup literal handling v3

Seems to be allot simpler, and also paves the
way for further improvements.

v2: rebased on master, use 0 in BUFFER_LOAD_FORMAT_XYZW,
    use VGPR0 in dummy EXP, avoid compiler warning, break
    after encoding the first literal.
v3: correctly use V_ADD_F32_e64

This is a candidate for the stable branch.

Signed-off-by: Christian König <christian.koenig@amd.com>
Reviewed-by: Tom Stellard <thomas.stellard@amd.com>

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@175354 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Christian Konig 2013-02-16 11:28:22 +00:00
parent 8e4eebcecf
commit e25e490793
10 changed files with 176 additions and 195 deletions

View File

@ -30,7 +30,6 @@ FunctionPass *createSIAnnotateControlFlowPass();
FunctionPass *createSIAssignInterpRegsPass(TargetMachine &tm);
FunctionPass *createSILowerControlFlowPass(TargetMachine &tm);
FunctionPass *createSICodeEmitterPass(formatted_raw_ostream &OS);
FunctionPass *createSILowerLiteralConstantsPass(TargetMachine &tm);
FunctionPass *createSIInsertWaits(TargetMachine &tm);
// Passes common to R600 and SI

View File

@ -91,8 +91,6 @@ void AMDGPUAsmPrinter::EmitProgramInfo(MachineFunction &MF) {
switch (reg) {
default: break;
case AMDGPU::EXEC:
case AMDGPU::SI_LITERAL_CONSTANT:
case AMDGPU::SREG_LIT_0:
case AMDGPU::M0:
continue;
}

View File

@ -145,7 +145,6 @@ bool AMDGPUPassConfig::addPreEmitPass() {
addPass(&FinalizeMachineBundlesID);
addPass(createR600LowerConstCopy(*TM));
} else {
addPass(createSILowerLiteralConstantsPass(*TM));
addPass(createSILowerControlFlowPass(*TM));
}

View File

@ -27,6 +27,13 @@
using namespace llvm;
namespace {
/// \brief Helper type used in encoding
typedef union {
int32_t I;
float F;
} IntFloatUnion;
class SIMCCodeEmitter : public AMDGPUMCCodeEmitter {
SIMCCodeEmitter(const SIMCCodeEmitter &); // DO NOT IMPLEMENT
void operator=(const SIMCCodeEmitter &); // DO NOT IMPLEMENT
@ -35,6 +42,15 @@ class SIMCCodeEmitter : public AMDGPUMCCodeEmitter {
const MCSubtargetInfo &STI;
MCContext &Ctx;
/// \brief Encode a sequence of registers with the correct alignment.
unsigned GPRAlign(const MCInst &MI, unsigned OpNo, unsigned shift) const;
/// \brief Can this operand also contain immediate values?
bool isSrcOperand(const MCInstrDesc &Desc, unsigned OpNo) const;
/// \brief Encode an fp or int literal
uint32_t getLitEncoding(const MCOperand &MO) const;
public:
SIMCCodeEmitter(const MCInstrInfo &mcii, const MCRegisterInfo &mri,
const MCSubtargetInfo &sti, MCContext &ctx)
@ -50,11 +66,6 @@ public:
virtual uint64_t getMachineOpValue(const MCInst &MI, const MCOperand &MO,
SmallVectorImpl<MCFixup> &Fixups) const;
public:
/// \brief Encode a sequence of registers with the correct alignment.
unsigned GPRAlign(const MCInst &MI, unsigned OpNo, unsigned shift) const;
/// \brief Encoding for when 2 consecutive registers are used
virtual unsigned GPR2AlignEncode(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixup) const;
@ -73,39 +84,131 @@ MCCodeEmitter *llvm::createSIMCCodeEmitter(const MCInstrInfo &MCII,
return new SIMCCodeEmitter(MCII, MRI, STI, Ctx);
}
bool SIMCCodeEmitter::isSrcOperand(const MCInstrDesc &Desc,
unsigned OpNo) const {
unsigned RegClass = Desc.OpInfo[OpNo].RegClass;
return (AMDGPU::SSrc_32RegClassID == RegClass) ||
(AMDGPU::SSrc_64RegClassID == RegClass) ||
(AMDGPU::VSrc_32RegClassID == RegClass) ||
(AMDGPU::VSrc_64RegClassID == RegClass);
}
uint32_t SIMCCodeEmitter::getLitEncoding(const MCOperand &MO) const {
IntFloatUnion Imm;
if (MO.isImm())
Imm.I = MO.getImm();
else if (MO.isFPImm())
Imm.F = MO.getFPImm();
else
return ~0;
if (Imm.I >= 0 && Imm.I <= 64)
return 128 + Imm.I;
if (Imm.I >= -16 && Imm.I <= -1)
return 192 + abs(Imm.I);
if (Imm.F == 0.5f)
return 240;
if (Imm.F == -0.5f)
return 241;
if (Imm.F == 1.0f)
return 242;
if (Imm.F == -1.0f)
return 243;
if (Imm.F == 2.0f)
return 244;
if (Imm.F == -2.0f)
return 245;
if (Imm.F == 4.0f)
return 246;
if (Imm.F == 4.0f)
return 247;
return 255;
}
void SIMCCodeEmitter::EncodeInstruction(const MCInst &MI, raw_ostream &OS,
SmallVectorImpl<MCFixup> &Fixups) const {
uint64_t Encoding = getBinaryCodeForInstr(MI, Fixups);
unsigned bytes = MCII.get(MI.getOpcode()).getSize();
const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
unsigned bytes = Desc.getSize();
for (unsigned i = 0; i < bytes; i++) {
OS.write((uint8_t) ((Encoding >> (8 * i)) & 0xff));
}
if (bytes > 4)
return;
// Check for additional literals in SRC0/1/2 (Op 1/2/3)
for (unsigned i = 0, e = MI.getNumOperands(); i < e; ++i) {
// Check if this operand should be encoded as [SV]Src
if (!isSrcOperand(Desc, i))
continue;
// Is this operand a literal immediate?
const MCOperand &Op = MI.getOperand(i);
if (getLitEncoding(Op) != 255)
continue;
// Yes! Encode it
IntFloatUnion Imm;
if (Op.isImm())
Imm.I = Op.getImm();
else
Imm.F = Op.getFPImm();
for (unsigned j = 0; j < 4; j++) {
OS.write((uint8_t) ((Imm.I >> (8 * j)) & 0xff));
}
// Only one literal value allowed
break;
}
}
uint64_t SIMCCodeEmitter::getMachineOpValue(const MCInst &MI,
const MCOperand &MO,
SmallVectorImpl<MCFixup> &Fixups) const {
if (MO.isReg()) {
if (MO.isReg())
return MRI.getEncodingValue(MO.getReg());
} else if (MO.isImm()) {
return MO.getImm();
} else if (MO.isFPImm()) {
// XXX: Not all instructions can use inline literals
// XXX: We should make sure this is a 32-bit constant
union {
float F;
uint32_t I;
} Imm;
Imm.F = MO.getFPImm();
return Imm.I;
} else if (MO.isExpr()) {
if (MO.isExpr()) {
const MCExpr *Expr = MO.getExpr();
MCFixupKind Kind = MCFixupKind(FK_PCRel_4);
Fixups.push_back(MCFixup::Create(0, Expr, Kind, MI.getLoc()));
return 0;
} else{
llvm_unreachable("Encoding of this operand type is not supported yet.");
}
// Figure out the operand number, needed for isSrcOperand check
unsigned OpNo = 0;
for (unsigned e = MI.getNumOperands(); OpNo < e; ++OpNo) {
if (&MO == &MI.getOperand(OpNo))
break;
}
const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
if (isSrcOperand(Desc, OpNo)) {
uint32_t Enc = getLitEncoding(MO);
if (Enc != ~0U && (Enc != 255 || Desc.getSize() == 4))
return Enc;
} else if (MO.isImm())
return MO.getImm();
llvm_unreachable("Encoding of this operand type is not supported yet.");
return 0;
}
@ -118,6 +221,7 @@ unsigned SIMCCodeEmitter::GPRAlign(const MCInst &MI, unsigned OpNo,
unsigned regCode = MRI.getEncodingValue(MI.getOperand(OpNo).getReg());
return (regCode & 0xff) >> shift;
}
unsigned SIMCCodeEmitter::GPR2AlignEncode(const MCInst &MI,
unsigned OpNo ,
SmallVectorImpl<MCFixup> &Fixup) const {

View File

@ -77,8 +77,8 @@ MachineBasicBlock * SITargetLowering::EmitInstrWithCustomInserter(
BuildMI(*BB, I, BB->findDebugLoc(I), TII->get(AMDGPU::V_ADD_F32_e64))
.addOperand(MI->getOperand(0))
.addOperand(MI->getOperand(1))
.addReg(AMDGPU::SREG_LIT_0)
.addReg(AMDGPU::SREG_LIT_0)
.addImm(0x80) // SRC1
.addImm(0x80) // SRC2
.addImm(0) // ABS
.addImm(1) // CLAMP
.addImm(0) // OMOD
@ -90,8 +90,8 @@ MachineBasicBlock * SITargetLowering::EmitInstrWithCustomInserter(
BuildMI(*BB, I, BB->findDebugLoc(I), TII->get(AMDGPU::V_ADD_F32_e64))
.addOperand(MI->getOperand(0))
.addOperand(MI->getOperand(1))
.addReg(AMDGPU::SREG_LIT_0)
.addReg(AMDGPU::SREG_LIT_0)
.addImm(0x80) // SRC1
.addImm(0x80) // SRC2
.addImm(1) // ABS
.addImm(0) // CLAMP
.addImm(0) // OMOD
@ -103,8 +103,8 @@ MachineBasicBlock * SITargetLowering::EmitInstrWithCustomInserter(
BuildMI(*BB, I, BB->findDebugLoc(I), TII->get(AMDGPU::V_ADD_F32_e64))
.addOperand(MI->getOperand(0))
.addOperand(MI->getOperand(1))
.addReg(AMDGPU::SREG_LIT_0)
.addReg(AMDGPU::SREG_LIT_0)
.addImm(0x80) // SRC1
.addImm(0x80) // SRC2
.addImm(0) // ABS
.addImm(0) // CLAMP
.addImm(0) // OMOD
@ -176,7 +176,7 @@ void SITargetLowering::LowerSI_V_CNDLT(MachineInstr *MI, MachineBasicBlock &BB,
BuildMI(BB, I, BB.findDebugLoc(I),
TII->get(AMDGPU::V_CMP_GT_F32_e32),
VCC)
.addReg(AMDGPU::SREG_LIT_0)
.addImm(0)
.addOperand(MI->getOperand(1));
BuildMI(BB, I, BB.findDebugLoc(I), TII->get(AMDGPU::V_CNDMASK_B32_e32))

View File

@ -68,7 +68,7 @@ SIInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
MachineInstr * SIInstrInfo::getMovImmInstr(MachineFunction *MF, unsigned DstReg,
int64_t Imm) const {
MachineInstr * MI = MF->CreateMachineInstr(get(AMDGPU::V_MOV_IMM_I32), DebugLoc());
MachineInstr * MI = MF->CreateMachineInstr(get(AMDGPU::V_MOV_B32_e32), DebugLoc());
MachineInstrBuilder MIB(*MF, MI);
MIB.addReg(DstReg, RegState::Define);
MIB.addImm(Imm);
@ -84,9 +84,6 @@ bool SIInstrInfo::isMov(unsigned Opcode) const {
case AMDGPU::S_MOV_B64:
case AMDGPU::V_MOV_B32_e32:
case AMDGPU::V_MOV_B32_e64:
case AMDGPU::V_MOV_IMM_F32:
case AMDGPU::V_MOV_IMM_I32:
case AMDGPU::S_MOV_IMM_I32:
return true;
}
}

View File

@ -1018,45 +1018,6 @@ def S_BFE_I64 : SOP2_64 <0x0000002a, "S_BFE_I64", []>;
//def S_CBRANCH_G_FORK : SOP2_ <0x0000002b, "S_CBRANCH_G_FORK", []>;
def S_ABSDIFF_I32 : SOP2_32 <0x0000002c, "S_ABSDIFF_I32", []>;
class V_MOV_IMM <ValueType type, Operand immType, SDNode immNode> : InstSI <
(outs VReg_32:$dst),
(ins immType:$src0),
"V_MOV_IMM",
[(set VReg_32:$dst, (type immNode:$src0))]
>;
let isCodeGenOnly = 1, isPseudo = 1 in {
def V_MOV_IMM_I32 : V_MOV_IMM<i32, i32imm, imm>;
def V_MOV_IMM_F32 : V_MOV_IMM<f32, f32imm, fpimm>;
def S_MOV_IMM_I32 : InstSI <
(outs SReg_32:$dst),
(ins i32imm:$src0),
"S_MOV_IMM_I32",
[(set SReg_32:$dst, (imm:$src0))]
>;
} // End isCodeGenOnly, isPseudo = 1
// i64 immediates aren't supported in hardware, split it into two 32bit values
def : Pat <
(i64 imm:$imm),
(INSERT_SUBREG (INSERT_SUBREG (i64 (IMPLICIT_DEF)),
(S_MOV_IMM_I32 (LO32 imm:$imm)), sub0),
(S_MOV_IMM_I32 (HI32 imm:$imm)), sub1)
>;
class SI_LOAD_LITERAL<Operand ImmType> :
Enc32 <(outs), (ins ImmType:$imm), "LOAD_LITERAL $imm", []> {
bits<32> imm;
let Inst{31-0} = imm;
}
def SI_LOAD_LITERAL_I32 : SI_LOAD_LITERAL<i32imm>;
def SI_LOAD_LITERAL_F32 : SI_LOAD_LITERAL<f32imm>;
let isCodeGenOnly = 1, isPseudo = 1 in {
def SET_M0 : InstSI <
@ -1173,7 +1134,7 @@ def SI_KILL : InstSI <
def : Pat <
(int_AMDGPU_kilp),
(SI_KILL (V_MOV_IMM_I32 0xbf800000))
(SI_KILL (V_MOV_B32_e32 0xbf800000))
>;
/* int_SI_vs_load_input */
@ -1182,7 +1143,7 @@ def : Pat<
VReg_32:$buf_idx_vgpr),
(BUFFER_LOAD_FORMAT_XYZW imm:$attr_offset, 0, 1, 0, 0, 0,
VReg_32:$buf_idx_vgpr, SReg_128:$tlst,
0, 0, (i32 SREG_LIT_0))
0, 0, 0)
>;
/* int_SI_export */
@ -1319,6 +1280,38 @@ def : Pat <
(COPY_TO_REGCLASS SReg_64:$vcc, VCCReg)
>;
/********** ================== **********/
/********** Immediate Patterns **********/
/********** ================== **********/
def : Pat <
(i32 imm:$imm),
(V_MOV_B32_e32 imm:$imm)
>;
def : Pat <
(f32 fpimm:$imm),
(V_MOV_B32_e32 fpimm:$imm)
>;
def : Pat <
(i32 imm:$imm),
(S_MOV_B32 imm:$imm)
>;
def : Pat <
(f32 fpimm:$imm),
(S_MOV_B32 fpimm:$imm)
>;
// i64 immediates aren't supported in hardware, split it into two 32bit values
def : Pat <
(i64 imm:$imm),
(INSERT_SUBREG (INSERT_SUBREG (i64 (IMPLICIT_DEF)),
(S_MOV_B32 (i32 (LO32 imm:$imm))), sub0),
(S_MOV_B32 (i32 (HI32 imm:$imm))), sub1)
>;
/********** ===================== **********/
/********** Interpolation Paterns **********/
/********** ===================== **********/
@ -1397,12 +1390,12 @@ def : Pat<
def : Pat <
(fcos VSrc_32:$src0),
(V_COS_F32_e32 (V_MUL_F32_e32 VSrc_32:$src0, (V_MOV_IMM_I32 CONST.TWO_PI_INV)))
(V_COS_F32_e32 (V_MUL_F32_e32 VSrc_32:$src0, (V_MOV_B32_e32 CONST.TWO_PI_INV)))
>;
def : Pat <
(fsin VSrc_32:$src0),
(V_SIN_F32_e32 (V_MUL_F32_e32 VSrc_32:$src0, (V_MOV_IMM_I32 CONST.TWO_PI_INV)))
(V_SIN_F32_e32 (V_MUL_F32_e32 VSrc_32:$src0, (V_MOV_B32_e32 CONST.TWO_PI_INV)))
>;
def : Pat <
@ -1448,7 +1441,7 @@ multiclass SMRD_Pattern <SMRD Instr_IMM, SMRD Instr_SGPR, ValueType vt> {
// 2. Offset loaded in an 32bit SGPR
def : Pat <
(constant_load (SIadd64bit32bit SReg_64:$sbase, imm:$offset)),
(vt (Instr_SGPR SReg_64:$sbase, (S_MOV_IMM_I32 imm:$offset)))
(vt (Instr_SGPR SReg_64:$sbase, (S_MOV_B32 imm:$offset)))
>;
// 3. No offset at all

View File

@ -158,10 +158,10 @@ void SILowerControlFlowPass::SkipIfDead(MachineInstr &MI) {
.addImm(0)
.addImm(1)
.addImm(1)
.addReg(AMDGPU::SREG_LIT_0)
.addReg(AMDGPU::SREG_LIT_0)
.addReg(AMDGPU::SREG_LIT_0)
.addReg(AMDGPU::SREG_LIT_0);
.addReg(AMDGPU::VGPR0)
.addReg(AMDGPU::VGPR0)
.addReg(AMDGPU::VGPR0)
.addReg(AMDGPU::VGPR0);
// ... and terminate wavefront
BuildMI(MBB, Insert, DL, TII->get(AMDGPU::S_ENDPGM));
@ -296,7 +296,7 @@ void SILowerControlFlowPass::Kill(MachineInstr &MI) {
// Clear this pixel from the exec mask if the operand is negative
BuildMI(MBB, &MI, DL, TII->get(AMDGPU::V_CMPX_LE_F32_e32), AMDGPU::VCC)
.addReg(AMDGPU::SREG_LIT_0)
.addImm(0)
.addOperand(MI.getOperand(0));
MI.eraseFromParent();

View File

@ -1,107 +0,0 @@
//===-- SILowerLiteralConstants.cpp - Lower intrs using literal constants--===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
/// \file
/// \brief This pass performs the following transformation on instructions with
/// literal constants:
///
/// %VGPR0 = V_MOV_IMM_I32 1
///
/// becomes:
///
/// BUNDLE
/// * %VGPR = V_MOV_B32_32 SI_LITERAL_CONSTANT
/// * SI_LOAD_LITERAL 1
///
/// The resulting sequence matches exactly how the hardware handles immediate
/// operands, so this transformation greatly simplifies the code generator.
///
/// Only the *_MOV_IMM_* support immediate operands at the moment, but when
/// support for immediate operands is added to other instructions, they
/// will be lowered here as well.
//===----------------------------------------------------------------------===//
#include "AMDGPU.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineInstrBundle.h"
using namespace llvm;
namespace {
class SILowerLiteralConstantsPass : public MachineFunctionPass {
private:
static char ID;
const TargetInstrInfo *TII;
public:
SILowerLiteralConstantsPass(TargetMachine &tm) :
MachineFunctionPass(ID), TII(tm.getInstrInfo()) { }
virtual bool runOnMachineFunction(MachineFunction &MF);
const char *getPassName() const {
return "SI Lower literal constants pass";
}
};
} // End anonymous namespace
char SILowerLiteralConstantsPass::ID = 0;
FunctionPass *llvm::createSILowerLiteralConstantsPass(TargetMachine &tm) {
return new SILowerLiteralConstantsPass(tm);
}
bool SILowerLiteralConstantsPass::runOnMachineFunction(MachineFunction &MF) {
for (MachineFunction::iterator BB = MF.begin(), BB_E = MF.end();
BB != BB_E; ++BB) {
MachineBasicBlock &MBB = *BB;
for (MachineBasicBlock::iterator I = MBB.begin(), Next = llvm::next(I);
I != MBB.end(); I = Next) {
Next = llvm::next(I);
MachineInstr &MI = *I;
switch (MI.getOpcode()) {
default: break;
case AMDGPU::S_MOV_IMM_I32:
case AMDGPU::V_MOV_IMM_F32:
case AMDGPU::V_MOV_IMM_I32: {
unsigned MovOpcode;
unsigned LoadLiteralOpcode;
MachineOperand LiteralOp = MI.getOperand(1);
if (AMDGPU::VReg_32RegClass.contains(MI.getOperand(0).getReg())) {
MovOpcode = AMDGPU::V_MOV_B32_e32;
} else {
MovOpcode = AMDGPU::S_MOV_B32;
}
if (LiteralOp.isImm()) {
LoadLiteralOpcode = AMDGPU::SI_LOAD_LITERAL_I32;
} else {
LoadLiteralOpcode = AMDGPU::SI_LOAD_LITERAL_F32;
}
MIBundleBuilder Bundle(MBB, I);
Bundle
.append(BuildMI(MF, MBB.findDebugLoc(I), TII->get(MovOpcode),
MI.getOperand(0).getReg())
.addReg(AMDGPU::SI_LITERAL_CONSTANT))
.append(BuildMI(MF, MBB.findDebugLoc(I),
TII->get(LoadLiteralOpcode))
.addOperand(MI.getOperand(1)));
llvm::finalizeBundle(MBB, Bundle.begin());
MI.eraseFromParent();
break;
}
}
}
}
return false;
}

View File

@ -22,8 +22,6 @@ def EXEC_LO : SIReg <"EXEC LO", 126>;
def EXEC_HI : SIReg <"EXEC HI", 127>;
def EXEC : SI_64<"EXEC", [EXEC_LO, EXEC_HI], 126>;
def SCC : SIReg<"SCC", 253>;
def SREG_LIT_0 : SIReg <"S LIT 0", 128>;
def SI_LITERAL_CONSTANT : SIReg<"LITERAL CONSTANT", 255>;
def M0 : SIReg <"M0", 124>;
//Interpolation registers
@ -136,7 +134,7 @@ def VGPR_512 : RegisterTuples<[sub0, sub1, sub2, sub3, sub4, sub5, sub6, sub7,
// Register class for all scalar registers (SGPRs + Special Registers)
def SReg_32 : RegisterClass<"AMDGPU", [f32, i32], 32,
(add SGPR_32, SREG_LIT_0, M0, EXEC_LO, EXEC_HI)
(add SGPR_32, M0, EXEC_LO, EXEC_HI)
>;
def SReg_64 : RegisterClass<"AMDGPU", [i64], 64, (add SGPR_64, VCC, EXEC)>;