2016-12-12 23:23:53 +01:00
|
|
|
//===-- SIMCCodeEmitter.cpp - SI Code Emitter -----------------------------===//
|
2012-12-11 22:25:42 +01:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
/// \file
|
|
|
|
/// \brief The SI code emitter produces machine code that can be executed
|
|
|
|
/// directly on the GPU device.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2014-07-21 16:01:14 +02:00
|
|
|
#include "AMDGPU.h"
|
2014-07-21 16:01:08 +02:00
|
|
|
#include "MCTargetDesc/AMDGPUFixupKinds.h"
|
2015-01-14 12:23:27 +01:00
|
|
|
#include "MCTargetDesc/AMDGPUMCCodeEmitter.h"
|
|
|
|
#include "MCTargetDesc/AMDGPUMCTargetDesc.h"
|
AMDGPU] Assembler: better support for immediate literals in assembler.
Summary:
Prevously assembler parsed all literals as either 32-bit integers or 32-bit floating-point values. Because of this we couldn't support f64 literals.
E.g. in instruction "v_fract_f64 v[0:1], 0.5", literal 0.5 was encoded as 32-bit literal 0x3f000000, which is incorrect and will be interpreted as 3.0517578125E-5 instead of 0.5. Correct encoding is inline constant 240 (optimal) or 32-bit literal 0x3FE00000 at least.
With this change the way immediate literals are parsed is changed. All literals are always parsed as 64-bit values either integer or floating-point. Then we convert parsed literals to correct form based on information about type of operand parsed (was literal floating or binary) and type of expected instruction operands (is this f32/64 or b32/64 instruction).
Here are rules how we convert literals:
- We parsed fp literal:
- Instruction expects 64-bit operand:
- If parsed literal is inlinable (e.g. v_fract_f64_e32 v[0:1], 0.5)
- then we do nothing this literal
- Else if literal is not-inlinable but instruction requires to inline it (e.g. this is e64 encoding, v_fract_f64_e64 v[0:1], 1.5)
- report error
- Else literal is not-inlinable but we can encode it as additional 32-bit literal constant
- If instruction expect fp operand type (f64)
- Check if low 32 bits of literal are zeroes (e.g. v_fract_f64 v[0:1], 1.5)
- If so then do nothing
- Else (e.g. v_fract_f64 v[0:1], 3.1415)
- report warning that low 32 bits will be set to zeroes and precision will be lost
- set low 32 bits of literal to zeroes
- Instruction expects integer operand type (e.g. s_mov_b64_e32 s[0:1], 1.5)
- report error as it is unclear how to encode this literal
- Instruction expects 32-bit operand:
- Convert parsed 64 bit fp literal to 32 bit fp. Allow lose of precision but not overflow or underflow
- Is this literal inlinable and are we required to inline literal (e.g. v_trunc_f32_e64 v0, 0.5)
- do nothing
- Else report error
- Do nothing. We can encode any other 32-bit fp literal (e.g. v_trunc_f32 v0, 10000000.0)
- Parsed binary literal:
- Is this literal inlinable (e.g. v_trunc_f32_e32 v0, 35)
- do nothing
- Else, are we required to inline this literal (e.g. v_trunc_f32_e64 v0, 35)
- report error
- Else, literal is not-inlinable and we are not required to inline it
- Are high 32 bit of literal zeroes or same as sign bit (32 bit)
- do nothing (e.g. v_trunc_f32 v0, 0xdeadbeef)
- Else
- report error (e.g. v_trunc_f32 v0, 0x123456789abcdef0)
For this change it is required that we know operand types of instruction (are they f32/64 or b32/64). I added several new register operands (they extend previous register operands) and set operand types to corresponding types:
'''
enum OperandType {
OPERAND_REG_IMM32_INT,
OPERAND_REG_IMM32_FP,
OPERAND_REG_INLINE_C_INT,
OPERAND_REG_INLINE_C_FP,
}
'''
This is not working yet:
- Several tests are failing
- Problems with predicate methods for inline immediates
- LLVM generated assembler parts try to select e64 encoding before e32.
More changes are required for several AsmOperands.
Reviewers: vpykhtin, tstellarAMD
Subscribers: arsenm, kzhuravl, artem.tamazov
Differential Revision: https://reviews.llvm.org/D22922
llvm-svn: 281050
2016-09-09 16:44:04 +02:00
|
|
|
#include "Utils/AMDGPUBaseInfo.h"
|
2012-12-11 22:25:42 +01:00
|
|
|
#include "llvm/MC/MCCodeEmitter.h"
|
|
|
|
#include "llvm/MC/MCContext.h"
|
2016-12-12 23:23:53 +01:00
|
|
|
#include "llvm/MC/MCExpr.h"
|
2013-01-02 11:22:59 +01:00
|
|
|
#include "llvm/MC/MCFixup.h"
|
2012-12-11 22:25:42 +01:00
|
|
|
#include "llvm/MC/MCInst.h"
|
2016-12-12 23:23:53 +01:00
|
|
|
#include "llvm/MC/MCInstrDesc.h"
|
2012-12-11 22:25:42 +01:00
|
|
|
#include "llvm/MC/MCInstrInfo.h"
|
|
|
|
#include "llvm/MC/MCRegisterInfo.h"
|
|
|
|
#include "llvm/MC/MCSubtargetInfo.h"
|
2016-08-26 19:58:37 +02:00
|
|
|
#include "llvm/MC/MCSymbol.h"
|
2016-12-12 23:23:53 +01:00
|
|
|
#include "llvm/Support/Casting.h"
|
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
|
|
#include "llvm/Support/MathExtras.h"
|
2012-12-11 22:25:42 +01:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2016-12-12 23:23:53 +01:00
|
|
|
#include <cassert>
|
|
|
|
#include <cstdint>
|
|
|
|
#include <cstdlib>
|
2012-12-11 22:25:42 +01:00
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
namespace {
|
2013-02-16 12:28:22 +01:00
|
|
|
|
2012-12-11 22:25:42 +01:00
|
|
|
class SIMCCodeEmitter : public AMDGPUMCCodeEmitter {
|
|
|
|
const MCRegisterInfo &MRI;
|
|
|
|
|
2013-02-16 12:28:22 +01:00
|
|
|
/// \brief Encode an fp or int literal
|
2016-12-10 01:39:12 +01:00
|
|
|
uint32_t getLitEncoding(const MCOperand &MO, const MCOperandInfo &OpInfo,
|
AMDGPU] Assembler: better support for immediate literals in assembler.
Summary:
Prevously assembler parsed all literals as either 32-bit integers or 32-bit floating-point values. Because of this we couldn't support f64 literals.
E.g. in instruction "v_fract_f64 v[0:1], 0.5", literal 0.5 was encoded as 32-bit literal 0x3f000000, which is incorrect and will be interpreted as 3.0517578125E-5 instead of 0.5. Correct encoding is inline constant 240 (optimal) or 32-bit literal 0x3FE00000 at least.
With this change the way immediate literals are parsed is changed. All literals are always parsed as 64-bit values either integer or floating-point. Then we convert parsed literals to correct form based on information about type of operand parsed (was literal floating or binary) and type of expected instruction operands (is this f32/64 or b32/64 instruction).
Here are rules how we convert literals:
- We parsed fp literal:
- Instruction expects 64-bit operand:
- If parsed literal is inlinable (e.g. v_fract_f64_e32 v[0:1], 0.5)
- then we do nothing this literal
- Else if literal is not-inlinable but instruction requires to inline it (e.g. this is e64 encoding, v_fract_f64_e64 v[0:1], 1.5)
- report error
- Else literal is not-inlinable but we can encode it as additional 32-bit literal constant
- If instruction expect fp operand type (f64)
- Check if low 32 bits of literal are zeroes (e.g. v_fract_f64 v[0:1], 1.5)
- If so then do nothing
- Else (e.g. v_fract_f64 v[0:1], 3.1415)
- report warning that low 32 bits will be set to zeroes and precision will be lost
- set low 32 bits of literal to zeroes
- Instruction expects integer operand type (e.g. s_mov_b64_e32 s[0:1], 1.5)
- report error as it is unclear how to encode this literal
- Instruction expects 32-bit operand:
- Convert parsed 64 bit fp literal to 32 bit fp. Allow lose of precision but not overflow or underflow
- Is this literal inlinable and are we required to inline literal (e.g. v_trunc_f32_e64 v0, 0.5)
- do nothing
- Else report error
- Do nothing. We can encode any other 32-bit fp literal (e.g. v_trunc_f32 v0, 10000000.0)
- Parsed binary literal:
- Is this literal inlinable (e.g. v_trunc_f32_e32 v0, 35)
- do nothing
- Else, are we required to inline this literal (e.g. v_trunc_f32_e64 v0, 35)
- report error
- Else, literal is not-inlinable and we are not required to inline it
- Are high 32 bit of literal zeroes or same as sign bit (32 bit)
- do nothing (e.g. v_trunc_f32 v0, 0xdeadbeef)
- Else
- report error (e.g. v_trunc_f32 v0, 0x123456789abcdef0)
For this change it is required that we know operand types of instruction (are they f32/64 or b32/64). I added several new register operands (they extend previous register operands) and set operand types to corresponding types:
'''
enum OperandType {
OPERAND_REG_IMM32_INT,
OPERAND_REG_IMM32_FP,
OPERAND_REG_INLINE_C_INT,
OPERAND_REG_INLINE_C_FP,
}
'''
This is not working yet:
- Several tests are failing
- Problems with predicate methods for inline immediates
- LLVM generated assembler parts try to select e64 encoding before e32.
More changes are required for several AsmOperands.
Reviewers: vpykhtin, tstellarAMD
Subscribers: arsenm, kzhuravl, artem.tamazov
Differential Revision: https://reviews.llvm.org/D22922
llvm-svn: 281050
2016-09-09 16:44:04 +02:00
|
|
|
const MCSubtargetInfo &STI) const;
|
2013-02-16 12:28:22 +01:00
|
|
|
|
2012-12-11 22:25:42 +01:00
|
|
|
public:
|
|
|
|
SIMCCodeEmitter(const MCInstrInfo &mcii, const MCRegisterInfo &mri,
|
2014-01-29 00:13:25 +01:00
|
|
|
MCContext &ctx)
|
Check that emitted instructions meet their predicates on all targets except ARM, Mips, and X86.
Summary:
* ARM is omitted from this patch because this check appears to expose bugs in this target.
* Mips is omitted from this patch because this check either detects bugs or deliberate
emission of instructions that don't satisfy their predicates. One deliberate
use is the SYNC instruction where the version with an operand is correctly
defined as requiring MIPS32 while the version without an operand is defined
as an alias of 'SYNC 0' and requires MIPS2.
* X86 is omitted from this patch because it doesn't use the tablegen-erated
MCCodeEmitter infrastructure.
Patches for ARM and Mips will follow.
Depends on D25617
Reviewers: tstellarAMD, jmolloy
Subscribers: wdng, jmolloy, aemerson, rengolin, arsenm, jyknight, nemanjai, nhaehnle, tstellarAMD, llvm-commits
Differential Revision: https://reviews.llvm.org/D25618
llvm-svn: 287439
2016-11-19 14:05:44 +01:00
|
|
|
: AMDGPUMCCodeEmitter(mcii), MRI(mri) {}
|
2016-12-12 23:23:53 +01:00
|
|
|
SIMCCodeEmitter(const SIMCCodeEmitter &) = delete;
|
|
|
|
SIMCCodeEmitter &operator=(const SIMCCodeEmitter &) = delete;
|
2012-12-11 22:25:42 +01:00
|
|
|
|
2014-01-24 18:20:08 +01:00
|
|
|
/// \brief Encode the instruction and write it to the OS.
|
2015-05-15 21:13:16 +02:00
|
|
|
void encodeInstruction(const MCInst &MI, raw_ostream &OS,
|
2014-01-29 00:13:07 +01:00
|
|
|
SmallVectorImpl<MCFixup> &Fixups,
|
2014-04-29 09:57:24 +02:00
|
|
|
const MCSubtargetInfo &STI) const override;
|
2012-12-11 22:25:42 +01:00
|
|
|
|
|
|
|
/// \returns the encoding for an MCOperand.
|
2014-04-29 09:57:24 +02:00
|
|
|
uint64_t getMachineOpValue(const MCInst &MI, const MCOperand &MO,
|
|
|
|
SmallVectorImpl<MCFixup> &Fixups,
|
|
|
|
const MCSubtargetInfo &STI) const override;
|
2014-07-21 16:01:08 +02:00
|
|
|
|
|
|
|
/// \brief Use a fixup to encode the simm16 field for SOPP branch
|
|
|
|
/// instructions.
|
|
|
|
unsigned getSOPPBrEncoding(const MCInst &MI, unsigned OpNo,
|
|
|
|
SmallVectorImpl<MCFixup> &Fixups,
|
|
|
|
const MCSubtargetInfo &STI) const override;
|
2017-06-26 05:01:36 +02:00
|
|
|
|
2017-06-21 10:53:38 +02:00
|
|
|
unsigned getSDWASrcEncoding(const MCInst &MI, unsigned OpNo,
|
|
|
|
SmallVectorImpl<MCFixup> &Fixups,
|
|
|
|
const MCSubtargetInfo &STI) const override;
|
|
|
|
|
|
|
|
unsigned getSDWAVopcDstEncoding(const MCInst &MI, unsigned OpNo,
|
|
|
|
SmallVectorImpl<MCFixup> &Fixups,
|
|
|
|
const MCSubtargetInfo &STI) const override;
|
2012-12-11 22:25:42 +01:00
|
|
|
};
|
|
|
|
|
2016-12-12 23:23:53 +01:00
|
|
|
} // end anonymous namespace
|
2012-12-11 22:25:42 +01:00
|
|
|
|
|
|
|
MCCodeEmitter *llvm::createSIMCCodeEmitter(const MCInstrInfo &MCII,
|
|
|
|
const MCRegisterInfo &MRI,
|
|
|
|
MCContext &Ctx) {
|
2014-01-29 00:13:25 +01:00
|
|
|
return new SIMCCodeEmitter(MCII, MRI, Ctx);
|
2012-12-11 22:25:42 +01:00
|
|
|
}
|
|
|
|
|
2015-02-13 20:05:03 +01:00
|
|
|
// Returns the encoding value to use if the given integer is an integer inline
|
|
|
|
// immediate value, or 0 if it is not.
|
|
|
|
template <typename IntTy>
|
|
|
|
static uint32_t getIntInlineImmEncoding(IntTy Imm) {
|
|
|
|
if (Imm >= 0 && Imm <= 64)
|
|
|
|
return 128 + Imm;
|
2013-02-16 12:28:22 +01:00
|
|
|
|
2015-02-13 20:05:03 +01:00
|
|
|
if (Imm >= -16 && Imm <= -1)
|
|
|
|
return 192 + std::abs(Imm);
|
2013-02-16 12:28:22 +01:00
|
|
|
|
2015-02-13 20:05:03 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2013-02-16 12:28:22 +01:00
|
|
|
|
2016-12-10 01:39:12 +01:00
|
|
|
static uint32_t getLit16Encoding(uint16_t Val, const MCSubtargetInfo &STI) {
|
|
|
|
uint16_t IntImm = getIntInlineImmEncoding(static_cast<int16_t>(Val));
|
|
|
|
if (IntImm != 0)
|
|
|
|
return IntImm;
|
|
|
|
|
|
|
|
if (Val == 0x3800) // 0.5
|
|
|
|
return 240;
|
|
|
|
|
|
|
|
if (Val == 0xB800) // -0.5
|
|
|
|
return 241;
|
|
|
|
|
|
|
|
if (Val == 0x3C00) // 1.0
|
|
|
|
return 242;
|
|
|
|
|
|
|
|
if (Val == 0xBC00) // -1.0
|
|
|
|
return 243;
|
|
|
|
|
|
|
|
if (Val == 0x4000) // 2.0
|
|
|
|
return 244;
|
|
|
|
|
|
|
|
if (Val == 0xC000) // -2.0
|
|
|
|
return 245;
|
|
|
|
|
|
|
|
if (Val == 0x4400) // 4.0
|
|
|
|
return 246;
|
|
|
|
|
|
|
|
if (Val == 0xC400) // -4.0
|
|
|
|
return 247;
|
|
|
|
|
|
|
|
if (Val == 0x3118 && // 1.0 / (2.0 * pi)
|
|
|
|
STI.getFeatureBits()[AMDGPU::FeatureInv2PiInlineImm])
|
|
|
|
return 248;
|
|
|
|
|
|
|
|
return 255;
|
|
|
|
}
|
|
|
|
|
AMDGPU] Assembler: better support for immediate literals in assembler.
Summary:
Prevously assembler parsed all literals as either 32-bit integers or 32-bit floating-point values. Because of this we couldn't support f64 literals.
E.g. in instruction "v_fract_f64 v[0:1], 0.5", literal 0.5 was encoded as 32-bit literal 0x3f000000, which is incorrect and will be interpreted as 3.0517578125E-5 instead of 0.5. Correct encoding is inline constant 240 (optimal) or 32-bit literal 0x3FE00000 at least.
With this change the way immediate literals are parsed is changed. All literals are always parsed as 64-bit values either integer or floating-point. Then we convert parsed literals to correct form based on information about type of operand parsed (was literal floating or binary) and type of expected instruction operands (is this f32/64 or b32/64 instruction).
Here are rules how we convert literals:
- We parsed fp literal:
- Instruction expects 64-bit operand:
- If parsed literal is inlinable (e.g. v_fract_f64_e32 v[0:1], 0.5)
- then we do nothing this literal
- Else if literal is not-inlinable but instruction requires to inline it (e.g. this is e64 encoding, v_fract_f64_e64 v[0:1], 1.5)
- report error
- Else literal is not-inlinable but we can encode it as additional 32-bit literal constant
- If instruction expect fp operand type (f64)
- Check if low 32 bits of literal are zeroes (e.g. v_fract_f64 v[0:1], 1.5)
- If so then do nothing
- Else (e.g. v_fract_f64 v[0:1], 3.1415)
- report warning that low 32 bits will be set to zeroes and precision will be lost
- set low 32 bits of literal to zeroes
- Instruction expects integer operand type (e.g. s_mov_b64_e32 s[0:1], 1.5)
- report error as it is unclear how to encode this literal
- Instruction expects 32-bit operand:
- Convert parsed 64 bit fp literal to 32 bit fp. Allow lose of precision but not overflow or underflow
- Is this literal inlinable and are we required to inline literal (e.g. v_trunc_f32_e64 v0, 0.5)
- do nothing
- Else report error
- Do nothing. We can encode any other 32-bit fp literal (e.g. v_trunc_f32 v0, 10000000.0)
- Parsed binary literal:
- Is this literal inlinable (e.g. v_trunc_f32_e32 v0, 35)
- do nothing
- Else, are we required to inline this literal (e.g. v_trunc_f32_e64 v0, 35)
- report error
- Else, literal is not-inlinable and we are not required to inline it
- Are high 32 bit of literal zeroes or same as sign bit (32 bit)
- do nothing (e.g. v_trunc_f32 v0, 0xdeadbeef)
- Else
- report error (e.g. v_trunc_f32 v0, 0x123456789abcdef0)
For this change it is required that we know operand types of instruction (are they f32/64 or b32/64). I added several new register operands (they extend previous register operands) and set operand types to corresponding types:
'''
enum OperandType {
OPERAND_REG_IMM32_INT,
OPERAND_REG_IMM32_FP,
OPERAND_REG_INLINE_C_INT,
OPERAND_REG_INLINE_C_FP,
}
'''
This is not working yet:
- Several tests are failing
- Problems with predicate methods for inline immediates
- LLVM generated assembler parts try to select e64 encoding before e32.
More changes are required for several AsmOperands.
Reviewers: vpykhtin, tstellarAMD
Subscribers: arsenm, kzhuravl, artem.tamazov
Differential Revision: https://reviews.llvm.org/D22922
llvm-svn: 281050
2016-09-09 16:44:04 +02:00
|
|
|
static uint32_t getLit32Encoding(uint32_t Val, const MCSubtargetInfo &STI) {
|
2015-02-13 20:05:03 +01:00
|
|
|
uint32_t IntImm = getIntInlineImmEncoding(static_cast<int32_t>(Val));
|
|
|
|
if (IntImm != 0)
|
|
|
|
return IntImm;
|
2013-02-16 12:28:22 +01:00
|
|
|
|
2015-02-13 20:05:03 +01:00
|
|
|
if (Val == FloatToBits(0.5f))
|
2013-02-16 12:28:22 +01:00
|
|
|
return 240;
|
|
|
|
|
2015-02-13 20:05:03 +01:00
|
|
|
if (Val == FloatToBits(-0.5f))
|
2013-02-16 12:28:22 +01:00
|
|
|
return 241;
|
|
|
|
|
2015-02-13 20:05:03 +01:00
|
|
|
if (Val == FloatToBits(1.0f))
|
2013-02-16 12:28:22 +01:00
|
|
|
return 242;
|
|
|
|
|
2015-02-13 20:05:03 +01:00
|
|
|
if (Val == FloatToBits(-1.0f))
|
2013-02-16 12:28:22 +01:00
|
|
|
return 243;
|
|
|
|
|
2015-02-13 20:05:03 +01:00
|
|
|
if (Val == FloatToBits(2.0f))
|
2013-02-16 12:28:22 +01:00
|
|
|
return 244;
|
|
|
|
|
2015-02-13 20:05:03 +01:00
|
|
|
if (Val == FloatToBits(-2.0f))
|
2013-02-16 12:28:22 +01:00
|
|
|
return 245;
|
|
|
|
|
2015-02-13 20:05:03 +01:00
|
|
|
if (Val == FloatToBits(4.0f))
|
2013-02-16 12:28:22 +01:00
|
|
|
return 246;
|
|
|
|
|
2015-02-13 20:05:03 +01:00
|
|
|
if (Val == FloatToBits(-4.0f))
|
2013-02-16 12:28:22 +01:00
|
|
|
return 247;
|
|
|
|
|
2016-10-29 06:05:06 +02:00
|
|
|
if (Val == 0x3e22f983 && // 1.0 / (2.0 * pi)
|
|
|
|
STI.getFeatureBits()[AMDGPU::FeatureInv2PiInlineImm])
|
AMDGPU] Assembler: better support for immediate literals in assembler.
Summary:
Prevously assembler parsed all literals as either 32-bit integers or 32-bit floating-point values. Because of this we couldn't support f64 literals.
E.g. in instruction "v_fract_f64 v[0:1], 0.5", literal 0.5 was encoded as 32-bit literal 0x3f000000, which is incorrect and will be interpreted as 3.0517578125E-5 instead of 0.5. Correct encoding is inline constant 240 (optimal) or 32-bit literal 0x3FE00000 at least.
With this change the way immediate literals are parsed is changed. All literals are always parsed as 64-bit values either integer or floating-point. Then we convert parsed literals to correct form based on information about type of operand parsed (was literal floating or binary) and type of expected instruction operands (is this f32/64 or b32/64 instruction).
Here are rules how we convert literals:
- We parsed fp literal:
- Instruction expects 64-bit operand:
- If parsed literal is inlinable (e.g. v_fract_f64_e32 v[0:1], 0.5)
- then we do nothing this literal
- Else if literal is not-inlinable but instruction requires to inline it (e.g. this is e64 encoding, v_fract_f64_e64 v[0:1], 1.5)
- report error
- Else literal is not-inlinable but we can encode it as additional 32-bit literal constant
- If instruction expect fp operand type (f64)
- Check if low 32 bits of literal are zeroes (e.g. v_fract_f64 v[0:1], 1.5)
- If so then do nothing
- Else (e.g. v_fract_f64 v[0:1], 3.1415)
- report warning that low 32 bits will be set to zeroes and precision will be lost
- set low 32 bits of literal to zeroes
- Instruction expects integer operand type (e.g. s_mov_b64_e32 s[0:1], 1.5)
- report error as it is unclear how to encode this literal
- Instruction expects 32-bit operand:
- Convert parsed 64 bit fp literal to 32 bit fp. Allow lose of precision but not overflow or underflow
- Is this literal inlinable and are we required to inline literal (e.g. v_trunc_f32_e64 v0, 0.5)
- do nothing
- Else report error
- Do nothing. We can encode any other 32-bit fp literal (e.g. v_trunc_f32 v0, 10000000.0)
- Parsed binary literal:
- Is this literal inlinable (e.g. v_trunc_f32_e32 v0, 35)
- do nothing
- Else, are we required to inline this literal (e.g. v_trunc_f32_e64 v0, 35)
- report error
- Else, literal is not-inlinable and we are not required to inline it
- Are high 32 bit of literal zeroes or same as sign bit (32 bit)
- do nothing (e.g. v_trunc_f32 v0, 0xdeadbeef)
- Else
- report error (e.g. v_trunc_f32 v0, 0x123456789abcdef0)
For this change it is required that we know operand types of instruction (are they f32/64 or b32/64). I added several new register operands (they extend previous register operands) and set operand types to corresponding types:
'''
enum OperandType {
OPERAND_REG_IMM32_INT,
OPERAND_REG_IMM32_FP,
OPERAND_REG_INLINE_C_INT,
OPERAND_REG_INLINE_C_FP,
}
'''
This is not working yet:
- Several tests are failing
- Problems with predicate methods for inline immediates
- LLVM generated assembler parts try to select e64 encoding before e32.
More changes are required for several AsmOperands.
Reviewers: vpykhtin, tstellarAMD
Subscribers: arsenm, kzhuravl, artem.tamazov
Differential Revision: https://reviews.llvm.org/D22922
llvm-svn: 281050
2016-09-09 16:44:04 +02:00
|
|
|
return 248;
|
|
|
|
|
2013-02-16 12:28:22 +01:00
|
|
|
return 255;
|
|
|
|
}
|
|
|
|
|
AMDGPU] Assembler: better support for immediate literals in assembler.
Summary:
Prevously assembler parsed all literals as either 32-bit integers or 32-bit floating-point values. Because of this we couldn't support f64 literals.
E.g. in instruction "v_fract_f64 v[0:1], 0.5", literal 0.5 was encoded as 32-bit literal 0x3f000000, which is incorrect and will be interpreted as 3.0517578125E-5 instead of 0.5. Correct encoding is inline constant 240 (optimal) or 32-bit literal 0x3FE00000 at least.
With this change the way immediate literals are parsed is changed. All literals are always parsed as 64-bit values either integer or floating-point. Then we convert parsed literals to correct form based on information about type of operand parsed (was literal floating or binary) and type of expected instruction operands (is this f32/64 or b32/64 instruction).
Here are rules how we convert literals:
- We parsed fp literal:
- Instruction expects 64-bit operand:
- If parsed literal is inlinable (e.g. v_fract_f64_e32 v[0:1], 0.5)
- then we do nothing this literal
- Else if literal is not-inlinable but instruction requires to inline it (e.g. this is e64 encoding, v_fract_f64_e64 v[0:1], 1.5)
- report error
- Else literal is not-inlinable but we can encode it as additional 32-bit literal constant
- If instruction expect fp operand type (f64)
- Check if low 32 bits of literal are zeroes (e.g. v_fract_f64 v[0:1], 1.5)
- If so then do nothing
- Else (e.g. v_fract_f64 v[0:1], 3.1415)
- report warning that low 32 bits will be set to zeroes and precision will be lost
- set low 32 bits of literal to zeroes
- Instruction expects integer operand type (e.g. s_mov_b64_e32 s[0:1], 1.5)
- report error as it is unclear how to encode this literal
- Instruction expects 32-bit operand:
- Convert parsed 64 bit fp literal to 32 bit fp. Allow lose of precision but not overflow or underflow
- Is this literal inlinable and are we required to inline literal (e.g. v_trunc_f32_e64 v0, 0.5)
- do nothing
- Else report error
- Do nothing. We can encode any other 32-bit fp literal (e.g. v_trunc_f32 v0, 10000000.0)
- Parsed binary literal:
- Is this literal inlinable (e.g. v_trunc_f32_e32 v0, 35)
- do nothing
- Else, are we required to inline this literal (e.g. v_trunc_f32_e64 v0, 35)
- report error
- Else, literal is not-inlinable and we are not required to inline it
- Are high 32 bit of literal zeroes or same as sign bit (32 bit)
- do nothing (e.g. v_trunc_f32 v0, 0xdeadbeef)
- Else
- report error (e.g. v_trunc_f32 v0, 0x123456789abcdef0)
For this change it is required that we know operand types of instruction (are they f32/64 or b32/64). I added several new register operands (they extend previous register operands) and set operand types to corresponding types:
'''
enum OperandType {
OPERAND_REG_IMM32_INT,
OPERAND_REG_IMM32_FP,
OPERAND_REG_INLINE_C_INT,
OPERAND_REG_INLINE_C_FP,
}
'''
This is not working yet:
- Several tests are failing
- Problems with predicate methods for inline immediates
- LLVM generated assembler parts try to select e64 encoding before e32.
More changes are required for several AsmOperands.
Reviewers: vpykhtin, tstellarAMD
Subscribers: arsenm, kzhuravl, artem.tamazov
Differential Revision: https://reviews.llvm.org/D22922
llvm-svn: 281050
2016-09-09 16:44:04 +02:00
|
|
|
static uint32_t getLit64Encoding(uint64_t Val, const MCSubtargetInfo &STI) {
|
2015-02-13 20:05:03 +01:00
|
|
|
uint32_t IntImm = getIntInlineImmEncoding(static_cast<int64_t>(Val));
|
|
|
|
if (IntImm != 0)
|
|
|
|
return IntImm;
|
|
|
|
|
|
|
|
if (Val == DoubleToBits(0.5))
|
|
|
|
return 240;
|
|
|
|
|
|
|
|
if (Val == DoubleToBits(-0.5))
|
|
|
|
return 241;
|
|
|
|
|
|
|
|
if (Val == DoubleToBits(1.0))
|
|
|
|
return 242;
|
|
|
|
|
|
|
|
if (Val == DoubleToBits(-1.0))
|
|
|
|
return 243;
|
|
|
|
|
|
|
|
if (Val == DoubleToBits(2.0))
|
|
|
|
return 244;
|
|
|
|
|
|
|
|
if (Val == DoubleToBits(-2.0))
|
|
|
|
return 245;
|
|
|
|
|
|
|
|
if (Val == DoubleToBits(4.0))
|
|
|
|
return 246;
|
|
|
|
|
|
|
|
if (Val == DoubleToBits(-4.0))
|
|
|
|
return 247;
|
|
|
|
|
2016-10-29 06:05:06 +02:00
|
|
|
if (Val == 0x3fc45f306dc9c882 && // 1.0 / (2.0 * pi)
|
|
|
|
STI.getFeatureBits()[AMDGPU::FeatureInv2PiInlineImm])
|
AMDGPU] Assembler: better support for immediate literals in assembler.
Summary:
Prevously assembler parsed all literals as either 32-bit integers or 32-bit floating-point values. Because of this we couldn't support f64 literals.
E.g. in instruction "v_fract_f64 v[0:1], 0.5", literal 0.5 was encoded as 32-bit literal 0x3f000000, which is incorrect and will be interpreted as 3.0517578125E-5 instead of 0.5. Correct encoding is inline constant 240 (optimal) or 32-bit literal 0x3FE00000 at least.
With this change the way immediate literals are parsed is changed. All literals are always parsed as 64-bit values either integer or floating-point. Then we convert parsed literals to correct form based on information about type of operand parsed (was literal floating or binary) and type of expected instruction operands (is this f32/64 or b32/64 instruction).
Here are rules how we convert literals:
- We parsed fp literal:
- Instruction expects 64-bit operand:
- If parsed literal is inlinable (e.g. v_fract_f64_e32 v[0:1], 0.5)
- then we do nothing this literal
- Else if literal is not-inlinable but instruction requires to inline it (e.g. this is e64 encoding, v_fract_f64_e64 v[0:1], 1.5)
- report error
- Else literal is not-inlinable but we can encode it as additional 32-bit literal constant
- If instruction expect fp operand type (f64)
- Check if low 32 bits of literal are zeroes (e.g. v_fract_f64 v[0:1], 1.5)
- If so then do nothing
- Else (e.g. v_fract_f64 v[0:1], 3.1415)
- report warning that low 32 bits will be set to zeroes and precision will be lost
- set low 32 bits of literal to zeroes
- Instruction expects integer operand type (e.g. s_mov_b64_e32 s[0:1], 1.5)
- report error as it is unclear how to encode this literal
- Instruction expects 32-bit operand:
- Convert parsed 64 bit fp literal to 32 bit fp. Allow lose of precision but not overflow or underflow
- Is this literal inlinable and are we required to inline literal (e.g. v_trunc_f32_e64 v0, 0.5)
- do nothing
- Else report error
- Do nothing. We can encode any other 32-bit fp literal (e.g. v_trunc_f32 v0, 10000000.0)
- Parsed binary literal:
- Is this literal inlinable (e.g. v_trunc_f32_e32 v0, 35)
- do nothing
- Else, are we required to inline this literal (e.g. v_trunc_f32_e64 v0, 35)
- report error
- Else, literal is not-inlinable and we are not required to inline it
- Are high 32 bit of literal zeroes or same as sign bit (32 bit)
- do nothing (e.g. v_trunc_f32 v0, 0xdeadbeef)
- Else
- report error (e.g. v_trunc_f32 v0, 0x123456789abcdef0)
For this change it is required that we know operand types of instruction (are they f32/64 or b32/64). I added several new register operands (they extend previous register operands) and set operand types to corresponding types:
'''
enum OperandType {
OPERAND_REG_IMM32_INT,
OPERAND_REG_IMM32_FP,
OPERAND_REG_INLINE_C_INT,
OPERAND_REG_INLINE_C_FP,
}
'''
This is not working yet:
- Several tests are failing
- Problems with predicate methods for inline immediates
- LLVM generated assembler parts try to select e64 encoding before e32.
More changes are required for several AsmOperands.
Reviewers: vpykhtin, tstellarAMD
Subscribers: arsenm, kzhuravl, artem.tamazov
Differential Revision: https://reviews.llvm.org/D22922
llvm-svn: 281050
2016-09-09 16:44:04 +02:00
|
|
|
return 248;
|
|
|
|
|
2015-02-13 20:05:03 +01:00
|
|
|
return 255;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t SIMCCodeEmitter::getLitEncoding(const MCOperand &MO,
|
2016-12-10 01:39:12 +01:00
|
|
|
const MCOperandInfo &OpInfo,
|
AMDGPU] Assembler: better support for immediate literals in assembler.
Summary:
Prevously assembler parsed all literals as either 32-bit integers or 32-bit floating-point values. Because of this we couldn't support f64 literals.
E.g. in instruction "v_fract_f64 v[0:1], 0.5", literal 0.5 was encoded as 32-bit literal 0x3f000000, which is incorrect and will be interpreted as 3.0517578125E-5 instead of 0.5. Correct encoding is inline constant 240 (optimal) or 32-bit literal 0x3FE00000 at least.
With this change the way immediate literals are parsed is changed. All literals are always parsed as 64-bit values either integer or floating-point. Then we convert parsed literals to correct form based on information about type of operand parsed (was literal floating or binary) and type of expected instruction operands (is this f32/64 or b32/64 instruction).
Here are rules how we convert literals:
- We parsed fp literal:
- Instruction expects 64-bit operand:
- If parsed literal is inlinable (e.g. v_fract_f64_e32 v[0:1], 0.5)
- then we do nothing this literal
- Else if literal is not-inlinable but instruction requires to inline it (e.g. this is e64 encoding, v_fract_f64_e64 v[0:1], 1.5)
- report error
- Else literal is not-inlinable but we can encode it as additional 32-bit literal constant
- If instruction expect fp operand type (f64)
- Check if low 32 bits of literal are zeroes (e.g. v_fract_f64 v[0:1], 1.5)
- If so then do nothing
- Else (e.g. v_fract_f64 v[0:1], 3.1415)
- report warning that low 32 bits will be set to zeroes and precision will be lost
- set low 32 bits of literal to zeroes
- Instruction expects integer operand type (e.g. s_mov_b64_e32 s[0:1], 1.5)
- report error as it is unclear how to encode this literal
- Instruction expects 32-bit operand:
- Convert parsed 64 bit fp literal to 32 bit fp. Allow lose of precision but not overflow or underflow
- Is this literal inlinable and are we required to inline literal (e.g. v_trunc_f32_e64 v0, 0.5)
- do nothing
- Else report error
- Do nothing. We can encode any other 32-bit fp literal (e.g. v_trunc_f32 v0, 10000000.0)
- Parsed binary literal:
- Is this literal inlinable (e.g. v_trunc_f32_e32 v0, 35)
- do nothing
- Else, are we required to inline this literal (e.g. v_trunc_f32_e64 v0, 35)
- report error
- Else, literal is not-inlinable and we are not required to inline it
- Are high 32 bit of literal zeroes or same as sign bit (32 bit)
- do nothing (e.g. v_trunc_f32 v0, 0xdeadbeef)
- Else
- report error (e.g. v_trunc_f32 v0, 0x123456789abcdef0)
For this change it is required that we know operand types of instruction (are they f32/64 or b32/64). I added several new register operands (they extend previous register operands) and set operand types to corresponding types:
'''
enum OperandType {
OPERAND_REG_IMM32_INT,
OPERAND_REG_IMM32_FP,
OPERAND_REG_INLINE_C_INT,
OPERAND_REG_INLINE_C_FP,
}
'''
This is not working yet:
- Several tests are failing
- Problems with predicate methods for inline immediates
- LLVM generated assembler parts try to select e64 encoding before e32.
More changes are required for several AsmOperands.
Reviewers: vpykhtin, tstellarAMD
Subscribers: arsenm, kzhuravl, artem.tamazov
Differential Revision: https://reviews.llvm.org/D22922
llvm-svn: 281050
2016-09-09 16:44:04 +02:00
|
|
|
const MCSubtargetInfo &STI) const {
|
2016-06-15 05:09:39 +02:00
|
|
|
int64_t Imm;
|
|
|
|
if (MO.isExpr()) {
|
2016-12-12 23:23:53 +01:00
|
|
|
const auto *C = dyn_cast<MCConstantExpr>(MO.getExpr());
|
2016-06-15 05:09:39 +02:00
|
|
|
if (!C)
|
|
|
|
return 255;
|
|
|
|
|
|
|
|
Imm = C->getValue();
|
|
|
|
} else {
|
2015-02-13 20:05:03 +01:00
|
|
|
|
2016-06-15 05:09:39 +02:00
|
|
|
assert(!MO.isFPImm());
|
|
|
|
|
|
|
|
if (!MO.isImm())
|
|
|
|
return ~0;
|
|
|
|
|
|
|
|
Imm = MO.getImm();
|
|
|
|
}
|
2015-02-13 20:05:03 +01:00
|
|
|
|
2017-02-27 19:49:11 +01:00
|
|
|
switch (OpInfo.OperandType) {
|
|
|
|
case AMDGPU::OPERAND_REG_IMM_INT32:
|
|
|
|
case AMDGPU::OPERAND_REG_IMM_FP32:
|
|
|
|
case AMDGPU::OPERAND_REG_INLINE_C_INT32:
|
|
|
|
case AMDGPU::OPERAND_REG_INLINE_C_FP32:
|
AMDGPU] Assembler: better support for immediate literals in assembler.
Summary:
Prevously assembler parsed all literals as either 32-bit integers or 32-bit floating-point values. Because of this we couldn't support f64 literals.
E.g. in instruction "v_fract_f64 v[0:1], 0.5", literal 0.5 was encoded as 32-bit literal 0x3f000000, which is incorrect and will be interpreted as 3.0517578125E-5 instead of 0.5. Correct encoding is inline constant 240 (optimal) or 32-bit literal 0x3FE00000 at least.
With this change the way immediate literals are parsed is changed. All literals are always parsed as 64-bit values either integer or floating-point. Then we convert parsed literals to correct form based on information about type of operand parsed (was literal floating or binary) and type of expected instruction operands (is this f32/64 or b32/64 instruction).
Here are rules how we convert literals:
- We parsed fp literal:
- Instruction expects 64-bit operand:
- If parsed literal is inlinable (e.g. v_fract_f64_e32 v[0:1], 0.5)
- then we do nothing this literal
- Else if literal is not-inlinable but instruction requires to inline it (e.g. this is e64 encoding, v_fract_f64_e64 v[0:1], 1.5)
- report error
- Else literal is not-inlinable but we can encode it as additional 32-bit literal constant
- If instruction expect fp operand type (f64)
- Check if low 32 bits of literal are zeroes (e.g. v_fract_f64 v[0:1], 1.5)
- If so then do nothing
- Else (e.g. v_fract_f64 v[0:1], 3.1415)
- report warning that low 32 bits will be set to zeroes and precision will be lost
- set low 32 bits of literal to zeroes
- Instruction expects integer operand type (e.g. s_mov_b64_e32 s[0:1], 1.5)
- report error as it is unclear how to encode this literal
- Instruction expects 32-bit operand:
- Convert parsed 64 bit fp literal to 32 bit fp. Allow lose of precision but not overflow or underflow
- Is this literal inlinable and are we required to inline literal (e.g. v_trunc_f32_e64 v0, 0.5)
- do nothing
- Else report error
- Do nothing. We can encode any other 32-bit fp literal (e.g. v_trunc_f32 v0, 10000000.0)
- Parsed binary literal:
- Is this literal inlinable (e.g. v_trunc_f32_e32 v0, 35)
- do nothing
- Else, are we required to inline this literal (e.g. v_trunc_f32_e64 v0, 35)
- report error
- Else, literal is not-inlinable and we are not required to inline it
- Are high 32 bit of literal zeroes or same as sign bit (32 bit)
- do nothing (e.g. v_trunc_f32 v0, 0xdeadbeef)
- Else
- report error (e.g. v_trunc_f32 v0, 0x123456789abcdef0)
For this change it is required that we know operand types of instruction (are they f32/64 or b32/64). I added several new register operands (they extend previous register operands) and set operand types to corresponding types:
'''
enum OperandType {
OPERAND_REG_IMM32_INT,
OPERAND_REG_IMM32_FP,
OPERAND_REG_INLINE_C_INT,
OPERAND_REG_INLINE_C_FP,
}
'''
This is not working yet:
- Several tests are failing
- Problems with predicate methods for inline immediates
- LLVM generated assembler parts try to select e64 encoding before e32.
More changes are required for several AsmOperands.
Reviewers: vpykhtin, tstellarAMD
Subscribers: arsenm, kzhuravl, artem.tamazov
Differential Revision: https://reviews.llvm.org/D22922
llvm-svn: 281050
2016-09-09 16:44:04 +02:00
|
|
|
return getLit32Encoding(static_cast<uint32_t>(Imm), STI);
|
2017-02-27 19:49:11 +01:00
|
|
|
|
|
|
|
case AMDGPU::OPERAND_REG_IMM_INT64:
|
|
|
|
case AMDGPU::OPERAND_REG_IMM_FP64:
|
|
|
|
case AMDGPU::OPERAND_REG_INLINE_C_INT64:
|
|
|
|
case AMDGPU::OPERAND_REG_INLINE_C_FP64:
|
2016-12-10 01:39:12 +01:00
|
|
|
return getLit64Encoding(static_cast<uint64_t>(Imm), STI);
|
2017-02-27 19:49:11 +01:00
|
|
|
|
|
|
|
case AMDGPU::OPERAND_REG_IMM_INT16:
|
|
|
|
case AMDGPU::OPERAND_REG_IMM_FP16:
|
|
|
|
case AMDGPU::OPERAND_REG_INLINE_C_INT16:
|
|
|
|
case AMDGPU::OPERAND_REG_INLINE_C_FP16:
|
2017-02-02 03:27:04 +01:00
|
|
|
// FIXME Is this correct? What do inline immediates do on SI for f16 src
|
|
|
|
// which does not have f16 support?
|
2016-12-10 01:39:12 +01:00
|
|
|
return getLit16Encoding(static_cast<uint16_t>(Imm), STI);
|
2017-02-27 19:49:11 +01:00
|
|
|
|
|
|
|
case AMDGPU::OPERAND_REG_INLINE_C_V2INT16:
|
|
|
|
case AMDGPU::OPERAND_REG_INLINE_C_V2FP16: {
|
|
|
|
uint16_t Lo16 = static_cast<uint16_t>(Imm);
|
|
|
|
uint32_t Encoding = getLit16Encoding(Lo16, STI);
|
|
|
|
return Encoding;
|
|
|
|
}
|
2016-12-10 01:39:12 +01:00
|
|
|
default:
|
|
|
|
llvm_unreachable("invalid operand size");
|
|
|
|
}
|
2015-02-13 20:05:03 +01:00
|
|
|
}
|
|
|
|
|
2015-05-15 21:13:16 +02:00
|
|
|
void SIMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
|
2014-01-29 00:13:07 +01:00
|
|
|
SmallVectorImpl<MCFixup> &Fixups,
|
|
|
|
const MCSubtargetInfo &STI) const {
|
Check that emitted instructions meet their predicates on all targets except ARM, Mips, and X86.
Summary:
* ARM is omitted from this patch because this check appears to expose bugs in this target.
* Mips is omitted from this patch because this check either detects bugs or deliberate
emission of instructions that don't satisfy their predicates. One deliberate
use is the SYNC instruction where the version with an operand is correctly
defined as requiring MIPS32 while the version without an operand is defined
as an alias of 'SYNC 0' and requires MIPS2.
* X86 is omitted from this patch because it doesn't use the tablegen-erated
MCCodeEmitter infrastructure.
Patches for ARM and Mips will follow.
Depends on D25617
Reviewers: tstellarAMD, jmolloy
Subscribers: wdng, jmolloy, aemerson, rengolin, arsenm, jyknight, nemanjai, nhaehnle, tstellarAMD, llvm-commits
Differential Revision: https://reviews.llvm.org/D25618
llvm-svn: 287439
2016-11-19 14:05:44 +01:00
|
|
|
verifyInstructionPredicates(MI,
|
|
|
|
computeAvailableFeatures(STI.getFeatureBits()));
|
2013-02-16 12:28:22 +01:00
|
|
|
|
2014-01-29 00:13:18 +01:00
|
|
|
uint64_t Encoding = getBinaryCodeForInstr(MI, Fixups, STI);
|
2013-02-16 12:28:22 +01:00
|
|
|
const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
|
|
|
|
unsigned bytes = Desc.getSize();
|
|
|
|
|
2012-12-11 22:25:42 +01:00
|
|
|
for (unsigned i = 0; i < bytes; i++) {
|
|
|
|
OS.write((uint8_t) ((Encoding >> (8 * i)) & 0xff));
|
|
|
|
}
|
2013-02-16 12:28:22 +01:00
|
|
|
|
|
|
|
if (bytes > 4)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Check for additional literals in SRC0/1/2 (Op 1/2/3)
|
2017-08-02 03:42:04 +02:00
|
|
|
for (unsigned i = 0, e = Desc.getNumOperands(); i < e; ++i) {
|
2013-02-16 12:28:22 +01:00
|
|
|
|
|
|
|
// Check if this operand should be encoded as [SV]Src
|
AMDGPU] Assembler: better support for immediate literals in assembler.
Summary:
Prevously assembler parsed all literals as either 32-bit integers or 32-bit floating-point values. Because of this we couldn't support f64 literals.
E.g. in instruction "v_fract_f64 v[0:1], 0.5", literal 0.5 was encoded as 32-bit literal 0x3f000000, which is incorrect and will be interpreted as 3.0517578125E-5 instead of 0.5. Correct encoding is inline constant 240 (optimal) or 32-bit literal 0x3FE00000 at least.
With this change the way immediate literals are parsed is changed. All literals are always parsed as 64-bit values either integer or floating-point. Then we convert parsed literals to correct form based on information about type of operand parsed (was literal floating or binary) and type of expected instruction operands (is this f32/64 or b32/64 instruction).
Here are rules how we convert literals:
- We parsed fp literal:
- Instruction expects 64-bit operand:
- If parsed literal is inlinable (e.g. v_fract_f64_e32 v[0:1], 0.5)
- then we do nothing this literal
- Else if literal is not-inlinable but instruction requires to inline it (e.g. this is e64 encoding, v_fract_f64_e64 v[0:1], 1.5)
- report error
- Else literal is not-inlinable but we can encode it as additional 32-bit literal constant
- If instruction expect fp operand type (f64)
- Check if low 32 bits of literal are zeroes (e.g. v_fract_f64 v[0:1], 1.5)
- If so then do nothing
- Else (e.g. v_fract_f64 v[0:1], 3.1415)
- report warning that low 32 bits will be set to zeroes and precision will be lost
- set low 32 bits of literal to zeroes
- Instruction expects integer operand type (e.g. s_mov_b64_e32 s[0:1], 1.5)
- report error as it is unclear how to encode this literal
- Instruction expects 32-bit operand:
- Convert parsed 64 bit fp literal to 32 bit fp. Allow lose of precision but not overflow or underflow
- Is this literal inlinable and are we required to inline literal (e.g. v_trunc_f32_e64 v0, 0.5)
- do nothing
- Else report error
- Do nothing. We can encode any other 32-bit fp literal (e.g. v_trunc_f32 v0, 10000000.0)
- Parsed binary literal:
- Is this literal inlinable (e.g. v_trunc_f32_e32 v0, 35)
- do nothing
- Else, are we required to inline this literal (e.g. v_trunc_f32_e64 v0, 35)
- report error
- Else, literal is not-inlinable and we are not required to inline it
- Are high 32 bit of literal zeroes or same as sign bit (32 bit)
- do nothing (e.g. v_trunc_f32 v0, 0xdeadbeef)
- Else
- report error (e.g. v_trunc_f32 v0, 0x123456789abcdef0)
For this change it is required that we know operand types of instruction (are they f32/64 or b32/64). I added several new register operands (they extend previous register operands) and set operand types to corresponding types:
'''
enum OperandType {
OPERAND_REG_IMM32_INT,
OPERAND_REG_IMM32_FP,
OPERAND_REG_INLINE_C_INT,
OPERAND_REG_INLINE_C_FP,
}
'''
This is not working yet:
- Several tests are failing
- Problems with predicate methods for inline immediates
- LLVM generated assembler parts try to select e64 encoding before e32.
More changes are required for several AsmOperands.
Reviewers: vpykhtin, tstellarAMD
Subscribers: arsenm, kzhuravl, artem.tamazov
Differential Revision: https://reviews.llvm.org/D22922
llvm-svn: 281050
2016-09-09 16:44:04 +02:00
|
|
|
if (!AMDGPU::isSISrcOperand(Desc, i))
|
2013-02-16 12:28:22 +01:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// Is this operand a literal immediate?
|
|
|
|
const MCOperand &Op = MI.getOperand(i);
|
2016-12-10 01:39:12 +01:00
|
|
|
if (getLitEncoding(Op, Desc.OpInfo[i], STI) != 255)
|
2013-02-16 12:28:22 +01:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// Yes! Encode it
|
2015-02-13 20:05:07 +01:00
|
|
|
int64_t Imm = 0;
|
|
|
|
|
2013-02-16 12:28:22 +01:00
|
|
|
if (Op.isImm())
|
2015-02-13 20:05:07 +01:00
|
|
|
Imm = Op.getImm();
|
2016-06-15 05:09:39 +02:00
|
|
|
else if (Op.isExpr()) {
|
2016-12-12 23:23:53 +01:00
|
|
|
if (const auto *C = dyn_cast<MCConstantExpr>(Op.getExpr()))
|
2016-06-15 05:09:39 +02:00
|
|
|
Imm = C->getValue();
|
|
|
|
|
|
|
|
} else if (!Op.isExpr()) // Exprs will be replaced with a fixup value.
|
2015-02-13 20:05:07 +01:00
|
|
|
llvm_unreachable("Must be immediate or expr");
|
2013-02-16 12:28:22 +01:00
|
|
|
|
|
|
|
for (unsigned j = 0; j < 4; j++) {
|
2015-02-13 20:05:07 +01:00
|
|
|
OS.write((uint8_t) ((Imm >> (8 * j)) & 0xff));
|
2013-02-16 12:28:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Only one literal value allowed
|
|
|
|
break;
|
|
|
|
}
|
2012-12-11 22:25:42 +01:00
|
|
|
}
|
|
|
|
|
2014-07-21 16:01:08 +02:00
|
|
|
unsigned SIMCCodeEmitter::getSOPPBrEncoding(const MCInst &MI, unsigned OpNo,
|
|
|
|
SmallVectorImpl<MCFixup> &Fixups,
|
|
|
|
const MCSubtargetInfo &STI) const {
|
|
|
|
const MCOperand &MO = MI.getOperand(OpNo);
|
2013-02-16 12:28:22 +01:00
|
|
|
|
|
|
|
if (MO.isExpr()) {
|
2012-12-17 16:14:54 +01:00
|
|
|
const MCExpr *Expr = MO.getExpr();
|
2014-07-21 16:01:08 +02:00
|
|
|
MCFixupKind Kind = (MCFixupKind)AMDGPU::fixup_si_sopp_br;
|
2015-05-15 21:13:05 +02:00
|
|
|
Fixups.push_back(MCFixup::create(0, Expr, Kind, MI.getLoc()));
|
2012-12-17 16:14:54 +01:00
|
|
|
return 0;
|
2012-12-11 22:25:42 +01:00
|
|
|
}
|
2013-02-16 12:28:22 +01:00
|
|
|
|
2014-07-21 16:01:08 +02:00
|
|
|
return getMachineOpValue(MI, MO, Fixups, STI);
|
|
|
|
}
|
|
|
|
|
2017-05-23 12:08:55 +02:00
|
|
|
unsigned
|
2017-06-21 10:53:38 +02:00
|
|
|
SIMCCodeEmitter::getSDWASrcEncoding(const MCInst &MI, unsigned OpNo,
|
|
|
|
SmallVectorImpl<MCFixup> &Fixups,
|
|
|
|
const MCSubtargetInfo &STI) const {
|
2017-05-26 17:52:00 +02:00
|
|
|
using namespace AMDGPU::SDWA;
|
2017-06-21 10:53:38 +02:00
|
|
|
|
2017-05-23 12:08:55 +02:00
|
|
|
uint64_t RegEnc = 0;
|
|
|
|
|
|
|
|
const MCOperand &MO = MI.getOperand(OpNo);
|
|
|
|
|
|
|
|
unsigned Reg = MO.getReg();
|
|
|
|
RegEnc |= MRI.getEncodingValue(Reg);
|
2017-05-26 17:52:00 +02:00
|
|
|
RegEnc &= SDWA9EncValues::SRC_VGPR_MASK;
|
2017-05-26 20:01:29 +02:00
|
|
|
if (AMDGPU::isSGPR(AMDGPU::mc2PseudoReg(Reg), &MRI)) {
|
2017-05-26 17:52:00 +02:00
|
|
|
RegEnc |= SDWA9EncValues::SRC_SGPR_MASK;
|
2017-05-23 12:08:55 +02:00
|
|
|
}
|
|
|
|
return RegEnc;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned
|
2017-06-21 10:53:38 +02:00
|
|
|
SIMCCodeEmitter::getSDWAVopcDstEncoding(const MCInst &MI, unsigned OpNo,
|
|
|
|
SmallVectorImpl<MCFixup> &Fixups,
|
|
|
|
const MCSubtargetInfo &STI) const {
|
2017-05-26 17:52:00 +02:00
|
|
|
using namespace AMDGPU::SDWA;
|
|
|
|
|
2017-05-23 12:08:55 +02:00
|
|
|
uint64_t RegEnc = 0;
|
|
|
|
|
|
|
|
const MCOperand &MO = MI.getOperand(OpNo);
|
|
|
|
|
|
|
|
unsigned Reg = MO.getReg();
|
|
|
|
if (Reg != AMDGPU::VCC) {
|
|
|
|
RegEnc |= MRI.getEncodingValue(Reg);
|
2017-05-26 17:52:00 +02:00
|
|
|
RegEnc &= SDWA9EncValues::VOPC_DST_SGPR_MASK;
|
|
|
|
RegEnc |= SDWA9EncValues::VOPC_DST_VCC_MASK;
|
2017-05-23 12:08:55 +02:00
|
|
|
}
|
|
|
|
return RegEnc;
|
|
|
|
}
|
|
|
|
|
2017-06-24 07:12:29 +02:00
|
|
|
static bool needsPCRel(const MCExpr *Expr) {
|
|
|
|
switch (Expr->getKind()) {
|
|
|
|
case MCExpr::SymbolRef:
|
|
|
|
return true;
|
|
|
|
case MCExpr::Binary: {
|
|
|
|
auto *BE = cast<MCBinaryExpr>(Expr);
|
|
|
|
if (BE->getOpcode() == MCBinaryExpr::Sub)
|
|
|
|
return false;
|
|
|
|
return needsPCRel(BE->getLHS()) || needsPCRel(BE->getRHS());
|
|
|
|
}
|
|
|
|
case MCExpr::Unary:
|
|
|
|
return needsPCRel(cast<MCUnaryExpr>(Expr)->getSubExpr());
|
|
|
|
case MCExpr::Target:
|
|
|
|
case MCExpr::Constant:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
llvm_unreachable("invalid kind");
|
|
|
|
}
|
|
|
|
|
2014-07-21 16:01:08 +02:00
|
|
|
uint64_t SIMCCodeEmitter::getMachineOpValue(const MCInst &MI,
|
|
|
|
const MCOperand &MO,
|
|
|
|
SmallVectorImpl<MCFixup> &Fixups,
|
|
|
|
const MCSubtargetInfo &STI) const {
|
|
|
|
if (MO.isReg())
|
|
|
|
return MRI.getEncodingValue(MO.getReg());
|
|
|
|
|
2016-06-15 05:09:39 +02:00
|
|
|
if (MO.isExpr() && MO.getExpr()->getKind() != MCExpr::Constant) {
|
2017-06-24 07:12:29 +02:00
|
|
|
// FIXME: If this is expression is PCRel or not should not depend on what
|
|
|
|
// the expression looks like. Given that this is just a general expression,
|
|
|
|
// it should probably be FK_Data_4 and whatever is producing
|
|
|
|
//
|
|
|
|
// s_add_u32 s2, s2, (extern_const_addrspace+16
|
|
|
|
//
|
|
|
|
// And expecting a PCRel should instead produce
|
|
|
|
//
|
|
|
|
// .Ltmp1:
|
|
|
|
// s_add_u32 s2, s2, (extern_const_addrspace+16)-.Ltmp1
|
2016-06-10 21:26:38 +02:00
|
|
|
MCFixupKind Kind;
|
2017-06-24 07:12:29 +02:00
|
|
|
if (needsPCRel(MO.getExpr()))
|
2016-06-14 22:29:59 +02:00
|
|
|
Kind = FK_PCRel_4;
|
2017-06-24 07:12:29 +02:00
|
|
|
else
|
|
|
|
Kind = FK_Data_4;
|
2016-06-14 22:29:59 +02:00
|
|
|
Fixups.push_back(MCFixup::create(4, MO.getExpr(), Kind, MI.getLoc()));
|
2014-07-21 16:01:14 +02:00
|
|
|
}
|
|
|
|
|
2013-02-16 12:28:22 +01:00
|
|
|
// 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());
|
AMDGPU] Assembler: better support for immediate literals in assembler.
Summary:
Prevously assembler parsed all literals as either 32-bit integers or 32-bit floating-point values. Because of this we couldn't support f64 literals.
E.g. in instruction "v_fract_f64 v[0:1], 0.5", literal 0.5 was encoded as 32-bit literal 0x3f000000, which is incorrect and will be interpreted as 3.0517578125E-5 instead of 0.5. Correct encoding is inline constant 240 (optimal) or 32-bit literal 0x3FE00000 at least.
With this change the way immediate literals are parsed is changed. All literals are always parsed as 64-bit values either integer or floating-point. Then we convert parsed literals to correct form based on information about type of operand parsed (was literal floating or binary) and type of expected instruction operands (is this f32/64 or b32/64 instruction).
Here are rules how we convert literals:
- We parsed fp literal:
- Instruction expects 64-bit operand:
- If parsed literal is inlinable (e.g. v_fract_f64_e32 v[0:1], 0.5)
- then we do nothing this literal
- Else if literal is not-inlinable but instruction requires to inline it (e.g. this is e64 encoding, v_fract_f64_e64 v[0:1], 1.5)
- report error
- Else literal is not-inlinable but we can encode it as additional 32-bit literal constant
- If instruction expect fp operand type (f64)
- Check if low 32 bits of literal are zeroes (e.g. v_fract_f64 v[0:1], 1.5)
- If so then do nothing
- Else (e.g. v_fract_f64 v[0:1], 3.1415)
- report warning that low 32 bits will be set to zeroes and precision will be lost
- set low 32 bits of literal to zeroes
- Instruction expects integer operand type (e.g. s_mov_b64_e32 s[0:1], 1.5)
- report error as it is unclear how to encode this literal
- Instruction expects 32-bit operand:
- Convert parsed 64 bit fp literal to 32 bit fp. Allow lose of precision but not overflow or underflow
- Is this literal inlinable and are we required to inline literal (e.g. v_trunc_f32_e64 v0, 0.5)
- do nothing
- Else report error
- Do nothing. We can encode any other 32-bit fp literal (e.g. v_trunc_f32 v0, 10000000.0)
- Parsed binary literal:
- Is this literal inlinable (e.g. v_trunc_f32_e32 v0, 35)
- do nothing
- Else, are we required to inline this literal (e.g. v_trunc_f32_e64 v0, 35)
- report error
- Else, literal is not-inlinable and we are not required to inline it
- Are high 32 bit of literal zeroes or same as sign bit (32 bit)
- do nothing (e.g. v_trunc_f32 v0, 0xdeadbeef)
- Else
- report error (e.g. v_trunc_f32 v0, 0x123456789abcdef0)
For this change it is required that we know operand types of instruction (are they f32/64 or b32/64). I added several new register operands (they extend previous register operands) and set operand types to corresponding types:
'''
enum OperandType {
OPERAND_REG_IMM32_INT,
OPERAND_REG_IMM32_FP,
OPERAND_REG_INLINE_C_INT,
OPERAND_REG_INLINE_C_FP,
}
'''
This is not working yet:
- Several tests are failing
- Problems with predicate methods for inline immediates
- LLVM generated assembler parts try to select e64 encoding before e32.
More changes are required for several AsmOperands.
Reviewers: vpykhtin, tstellarAMD
Subscribers: arsenm, kzhuravl, artem.tamazov
Differential Revision: https://reviews.llvm.org/D22922
llvm-svn: 281050
2016-09-09 16:44:04 +02:00
|
|
|
if (AMDGPU::isSISrcOperand(Desc, OpNo)) {
|
2016-12-10 01:39:12 +01:00
|
|
|
uint32_t Enc = getLitEncoding(MO, Desc.OpInfo[OpNo], STI);
|
2013-02-16 12:28:22 +01:00
|
|
|
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.");
|
2012-12-11 22:25:42 +01:00
|
|
|
return 0;
|
|
|
|
}
|