Commit cf9c12f8 by Jaydeep Patil Committed by Jim Stichnoth

[SubZero] lower float and double constants for MIPS

The patch emits constant pool for float and double constants. R=stichnot@chromium.org Review URL: https://codereview.chromium.org/2351583002 . Patch from Jaydeep Patil <jaydeep.patil@imgtec.com>.
parent 3b61d70e
...@@ -1420,12 +1420,19 @@ void TargetMIPS32::PostLoweringLegalizer::legalizeMov(InstMIPS32Mov *MovInstr) { ...@@ -1420,12 +1420,19 @@ void TargetMIPS32::PostLoweringLegalizer::legalizeMov(InstMIPS32Mov *MovInstr) {
} }
} else { } else {
// Dest is FPR and SrcR is GPR. Use mtc1. // Dest is FPR and SrcR is GPR. Use mtc1.
if (typeWidthInBytes(SrcR->getType()) == 8) { if (typeWidthInBytes(Dest->getType()) == 8) {
// Split it into two mtc1 instructions Variable *SrcGPRHi, *SrcGPRLo;
Variable *SrcGPRHi = Target->makeReg( // SrcR could be $zero which is i32
IceType_i32, RegMIPS32::get64PairFirstRegNum(SRegNum)); if (SRegNum == RegMIPS32::Reg_ZERO) {
Variable *SrcGPRLo = Target->makeReg( SrcGPRHi = Target->makeReg(IceType_i32, SRegNum);
IceType_i32, RegMIPS32::get64PairSecondRegNum(SRegNum)); SrcGPRLo = SrcGPRHi;
} else {
// Split it into two mtc1 instructions
SrcGPRHi = Target->makeReg(
IceType_i32, RegMIPS32::get64PairFirstRegNum(SRegNum));
SrcGPRLo = Target->makeReg(
IceType_i32, RegMIPS32::get64PairSecondRegNum(SRegNum));
}
Variable *DstFPRHi = Target->makeReg( Variable *DstFPRHi = Target->makeReg(
IceType_f32, RegMIPS32::get64PairFirstRegNum(DRegNum)); IceType_f32, RegMIPS32::get64PairFirstRegNum(DRegNum));
Variable *DstFPRLo = Target->makeReg( Variable *DstFPRLo = Target->makeReg(
...@@ -3362,9 +3369,104 @@ void TargetDataMIPS32::lowerGlobals(const VariableDeclarationList &Vars, ...@@ -3362,9 +3369,104 @@ void TargetDataMIPS32::lowerGlobals(const VariableDeclarationList &Vars,
} }
} }
namespace {
template <typename T> struct ConstantPoolEmitterTraits;
static_assert(sizeof(uint64_t) == 8,
"uint64_t is supposed to be 8 bytes wide.");
// TODO(jaydeep.patil): implement the following when implementing constant
// randomization:
// * template <> struct ConstantPoolEmitterTraits<uint8_t>
// * template <> struct ConstantPoolEmitterTraits<uint16_t>
// * template <> struct ConstantPoolEmitterTraits<uint32_t>
template <> struct ConstantPoolEmitterTraits<float> {
using ConstantType = ConstantFloat;
static constexpr Type IceType = IceType_f32;
// AsmTag and TypeName can't be constexpr because llvm::StringRef is unhappy
// about them being constexpr.
static const char AsmTag[];
static const char TypeName[];
static uint64_t bitcastToUint64(float Value) {
static_assert(sizeof(Value) == sizeof(uint32_t),
"Float should be 4 bytes.");
const uint32_t IntValue = Utils::bitCopy<uint32_t>(Value);
return static_cast<uint64_t>(IntValue);
}
};
const char ConstantPoolEmitterTraits<float>::AsmTag[] = ".word";
const char ConstantPoolEmitterTraits<float>::TypeName[] = "f32";
template <> struct ConstantPoolEmitterTraits<double> {
using ConstantType = ConstantDouble;
static constexpr Type IceType = IceType_f64;
static const char AsmTag[];
static const char TypeName[];
static uint64_t bitcastToUint64(double Value) {
static_assert(sizeof(double) == sizeof(uint64_t),
"Double should be 8 bytes.");
return Utils::bitCopy<uint64_t>(Value);
}
};
const char ConstantPoolEmitterTraits<double>::AsmTag[] = ".quad";
const char ConstantPoolEmitterTraits<double>::TypeName[] = "f64";
template <typename T>
void emitConstant(
Ostream &Str,
const typename ConstantPoolEmitterTraits<T>::ConstantType *Const) {
if (!BuildDefs::dump())
return;
using Traits = ConstantPoolEmitterTraits<T>;
Str << Const->getLabelName();
T Value = Const->getValue();
Str << ":\n\t" << Traits::AsmTag << "\t0x";
Str.write_hex(Traits::bitcastToUint64(Value));
Str << "\t/* " << Traits::TypeName << " " << Value << " */\n";
}
template <typename T> void emitConstantPool(GlobalContext *Ctx) {
if (!BuildDefs::dump())
return;
using Traits = ConstantPoolEmitterTraits<T>;
static constexpr size_t MinimumAlignment = 4;
SizeT Align = std::max(MinimumAlignment, typeAlignInBytes(Traits::IceType));
assert((Align % 4) == 0 && "Constants should be aligned");
Ostream &Str = Ctx->getStrEmit();
ConstantList Pool = Ctx->getConstantPool(Traits::IceType);
Str << "\t.section\t.rodata.cst" << Align << ",\"aM\",%progbits," << Align
<< "\n"
<< "\t.align\t" << (Align == 4 ? 2 : 3) << "\n";
if (getFlags().getReorderPooledConstants()) {
// TODO(jaydeep.patil): add constant pooling.
UnimplementedError(getFlags());
}
for (Constant *C : Pool) {
if (!C->getShouldBePooled()) {
continue;
}
emitConstant<T>(Str, llvm::dyn_cast<typename Traits::ConstantType>(C));
}
}
} // end of anonymous namespace
void TargetDataMIPS32::lowerConstants() { void TargetDataMIPS32::lowerConstants() {
if (getFlags().getDisableTranslation()) if (getFlags().getDisableTranslation())
return; return;
switch (getFlags().getOutFileType()) {
case FT_Elf: {
ELFObjectWriter *Writer = Ctx->getObjectWriter();
Writer->writeConstantPool<ConstantFloat>(IceType_f32);
Writer->writeConstantPool<ConstantDouble>(IceType_f64);
} break;
case FT_Asm:
case FT_Iasm: {
OstreamLocker _(Ctx);
emitConstantPool<float>(Ctx);
emitConstantPool<double>(Ctx);
break;
}
}
} }
void TargetDataMIPS32::lowerJumpTables() { void TargetDataMIPS32::lowerJumpTables() {
...@@ -3486,21 +3588,25 @@ Operand *TargetMIPS32::legalize(Operand *From, LegalMask Allowed, ...@@ -3486,21 +3588,25 @@ Operand *TargetMIPS32::legalize(Operand *From, LegalMask Allowed,
} }
return Reg; return Reg;
} else if (isScalarFloatingType(Ty)) { } else if (isScalarFloatingType(Ty)) {
// Load floats/doubles from literal pool.
auto *CFrom = llvm::cast<Constant>(From); auto *CFrom = llvm::cast<Constant>(From);
assert(CFrom->getShouldBePooled()); Variable *TReg = makeReg(Ty);
Constant *Offset = Ctx->getConstantSym(0, CFrom->getLabelName()); if (!CFrom->getShouldBePooled()) {
Variable *TReg1 = makeReg(getPointerType()); // Float/Double constant 0 is not pooled.
Variable *TReg2 = makeReg(Ty); Context.insert<InstFakeDef>(TReg);
Context.insert<InstFakeDef>(TReg2); _mov(TReg, getZero());
_lui(TReg1, Offset, RO_Hi); } else {
OperandMIPS32Mem *Addr = // Load floats/doubles from literal pool.
OperandMIPS32Mem::create(Func, Ty, TReg1, Offset); Constant *Offset = Ctx->getConstantSym(0, CFrom->getLabelName());
if (Ty == IceType_f32) Variable *TReg1 = makeReg(getPointerType());
_lwc1(TReg2, Addr, RO_Lo); _lui(TReg1, Offset, RO_Hi);
else OperandMIPS32Mem *Addr =
_ldc1(TReg2, Addr, RO_Lo); OperandMIPS32Mem::create(Func, Ty, TReg1, Offset);
return copyToReg(TReg2, RegNum); if (Ty == IceType_f32)
_lwc1(TReg, Addr, RO_Lo);
else
_ldc1(TReg, Addr, RO_Lo);
}
return copyToReg(TReg, RegNum);
} }
} }
......
...@@ -38,8 +38,9 @@ public: ...@@ -38,8 +38,9 @@ public:
if (auto *ConstDouble = llvm::dyn_cast<ConstantDouble>(C)) { if (auto *ConstDouble = llvm::dyn_cast<ConstantDouble>(C)) {
return !Utils::isPositiveZero(ConstDouble->getValue()); return !Utils::isPositiveZero(ConstDouble->getValue());
} }
if (llvm::isa<ConstantFloat>(C)) if (auto *ConstFloat = llvm::dyn_cast<ConstantFloat>(C)) {
return true; return !Utils::isPositiveZero(ConstFloat->getValue());
}
return false; return false;
} }
static std::unique_ptr<::Ice::TargetLowering> create(Cfg *Func) { static std::unique_ptr<::Ice::TargetLowering> create(Cfg *Func) {
...@@ -828,7 +829,6 @@ protected: ...@@ -828,7 +829,6 @@ protected:
private: private:
~TargetDataMIPS32() override = default; ~TargetDataMIPS32() override = default;
template <typename T> static void emitConstantPool(GlobalContext *Ctx);
}; };
class TargetHeaderMIPS32 final : public TargetHeaderLowering { class TargetHeaderMIPS32 final : public TargetHeaderLowering {
......
...@@ -5,6 +5,12 @@ ...@@ -5,6 +5,12 @@
; REQUIRES: allow_dump ; REQUIRES: allow_dump
; RUN: %if --need=target_MIPS32 --need=allow_dump \
; RUN: --command %p2i --filetype=asm --assemble --disassemble \
; RUN: --target mips32 -i %s --args -O2 --skip-unimplemented \
; RUN: | %if --need=target_MIPS32 --need=allow_dump \
; RUN: --command FileCheck --check-prefix MIPS32 %s
define internal void @consume_float(float %f) { define internal void @consume_float(float %f) {
ret void ret void
} }
...@@ -21,6 +27,18 @@ entry: ...@@ -21,6 +27,18 @@ entry:
call void @consume_double(double -0.0) call void @consume_double(double -0.0)
ret void ret void
} }
; MIPS32-LABEL: test_zeros
; MIPS32: mtc1 zero,[[REG:.*]]
; MIPS32: mov.s {{.*}},[[REG]]
; MIPS32: lui [[REG:.*]],{{.*}}: R_MIPS_HI16 .L$float$80000000
; MIPS32: lwc1 {{.*}},0([[REG]]) {{.*}}: R_MIPS_LO16 .L$float$80000000
; MIPS32: mtc1 zero,[[REGLo:.*]]
; MIPS32: mtc1 zero,[[REGHi:.*]]
; MIPS32: mov.d {{.*}},[[REGLo]]
; MIPS32: lui [[REG:.*]],{{.*}}: R_MIPS_HI16 .L$double$8000000000000000
; MIPS32: ldc1 {{.*}},0([[REG]]) {{.*}}: R_MIPS_LO16 .L$double$8000000000000000
; Parse the function, dump the bitcode back out, and stop without translating. ; Parse the function, dump the bitcode back out, and stop without translating.
; This tests that +0.0 and -0.0 aren't accidentally merged into a single ; This tests that +0.0 and -0.0 aren't accidentally merged into a single
; zero-valued constant pool entry. ; zero-valued constant pool entry.
...@@ -46,6 +64,26 @@ entry: ...@@ -46,6 +64,26 @@ entry:
call void @consume_double(double 0xFFF8000000000000) call void @consume_double(double 0xFFF8000000000000)
ret void ret void
} }
; MIPS32-LABEL: test_nans
; MIPS32: lui [[REG:.*]],{{.*}}: R_MIPS_HI16 .L$float$7fc00000
; MIPS32: lwc1 {{.*}},0([[REG]]) {{.*}}: R_MIPS_LO16 .L$float$7fc00000
; MIPS32: lui [[REG:.*]],{{.*}}: R_MIPS_HI16 .L$float$7fc00000
; MIPS32: lwc1 {{.*}},0([[REG]]) {{.*}}: R_MIPS_LO16 .L$float$7fc00000
; MIPS32: lui [[REG:.*]],{{.*}}: R_MIPS_HI16 .L$float$ffc00000
; MIPS32: lwc1 {{.*}},0([[REG]]) {{.*}}: R_MIPS_LO16 .L$float$ffc00000
; MIPS32: lui [[REG:.*]],{{.*}}: R_MIPS_HI16 .L$float$ffc00000
; MIPS32: lwc1 {{.*}},0([[REG]]) {{.*}}: R_MIPS_LO16 .L$float$ffc00000
; MIPS32: lui [[REG:.*]],{{.*}}: R_MIPS_HI16 .L$double$7ff8000000000000
; MIPS32: ldc1 {{.*}},0([[REG]]) {{.*}}: R_MIPS_LO16 .L$double$7ff8000000000000
; MIPS32: lui [[REG:.*]],{{.*}}: R_MIPS_HI16 .L$double$7ff8000000000000
; MIPS32: ldc1 {{.*}},0([[REG]]) {{.*}}: R_MIPS_LO16 .L$double$7ff8000000000000
; MIPS32: lui [[REG:.*]],{{.*}}: R_MIPS_HI16 .L$double$fff8000000000000
; MIPS32: ldc1 {{.*}},0([[REG]]) {{.*}}: R_MIPS_LO16 .L$double$fff8000000000000
; MIPS32: lui [[REG:.*]],{{.*}}: R_MIPS_HI16 .L$double$fff8000000000000
; MIPS32: ldc1 {{.*}},0([[REG]]) {{.*}}: R_MIPS_LO16 .L$double$fff8000000000000
; MIPS32: jr ra
; The following tests check the emitted constant pool entries and make sure ; The following tests check the emitted constant pool entries and make sure
; there is at most one entry for each NaN value. We have to run a separate test ; there is at most one entry for each NaN value. We have to run a separate test
; for each NaN because the constant pool entries may be emitted in any order. ; for each NaN because the constant pool entries may be emitted in any order.
...@@ -69,3 +107,22 @@ entry: ...@@ -69,3 +107,22 @@ entry:
; RUN: | FileCheck --check-prefix=NANS4 %s ; RUN: | FileCheck --check-prefix=NANS4 %s
; NANS4: double -nan ; NANS4: double -nan
; NANS4-NOT: double -nan ; NANS4-NOT: double -nan
; MIPS32 constant pool
; RUN: %if --need=target_MIPS32 --command %p2i \
; RUN: --target mips32 -i %s --filetype=asm --llvm-source \
; RUN: --args -O2 --skip-unimplemented \
; RUN: | %if --need=target_MIPS32 --command FileCheck \
; RUN: --check-prefix=MIPS32CP %s
; MIPS32CP-LABEL: .L$float$7fc00000:
; MIPS32CP: .word 0x7fc00000 /* f32 nan */
; MIPS32CP-LABEL: .L$float$80000000
; MIPS32CP: .word 0x80000000 /* f32 -0.000000e+00 */
; MIPS32CP-LABEL: .L$float$ffc00000
; MIPS32CP: .word 0xffc00000 /* f32 -nan */
; MIPS32CP-LABEL: .L$double$7ff8000000000000
; MIPS32CP: .quad 0x7ff8000000000000 /* f64 nan */
; MIPS32CP-LABEL: .L$double$8000000000000000
; MIPS32CP: .quad 0x8000000000000000 /* f64 -0.000000e+00 */
; MIPS32CP-LABEL: .L$double$fff8000000000000
; MIPS32CP: .quad 0xfff8000000000000 /* f64 -nan */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment