Chromium Code Reviews| Index: src/IceInstARM32.cpp |
| diff --git a/src/IceInstARM32.cpp b/src/IceInstARM32.cpp |
| index 5507b63fcffe938efd98d16cb7e21f3f473106c8..c995dc07d04759cc8ba3038bda4b4de506cfd430 100644 |
| --- a/src/IceInstARM32.cpp |
| +++ b/src/IceInstARM32.cpp |
| @@ -284,6 +284,87 @@ bool OperandARM32FlexImm::canHoldImm(uint32_t Immediate, uint32_t *RotateAmt, |
| return false; |
| } |
| +OperandARM32FlexFpImm::OperandARM32FlexFpImm(Cfg * /*Func*/, Type Ty, |
| + uint32_t ModifiedImm) |
| + : OperandARM32Flex(kFlexFpImm, Ty), ModifiedImm(ModifiedImm) {} |
| + |
| +bool OperandARM32FlexFpImm::canHoldImm(Operand *C, uint32_t *ModifiedImm) { |
| + switch (C->getType()) { |
| + default: |
| + llvm::report_fatal_error("Unhandled fp constant type."); |
| + case IceType_f32: { |
| + // We violate llvm naming conventions a bit here so that the constants are |
| + // named after the bit fields they represent. See "A7.5.1 Operation of |
| + // modified immediate constants, Floating-point" in the ARM ARM. |
| + static constexpr uint32_t a = 0x80000000; |
|
sehr
2015/11/13 21:56:29
0x80000000u?
John
2015/11/14 00:00:38
Done.
|
| + static constexpr uint32_t B = 0x40000000; |
| + static constexpr uint32_t bbbbb = 0x3E000000; |
| + static constexpr uint32_t cdefgh = 0x01F80000; |
| + static constexpr uint32_t AllowedBits = a | B | bbbbb | cdefgh; |
| + static_assert(AllowedBits == 0xFFF80000, |
|
sehr
2015/11/13 21:56:29
Ditto regarding u suffix, here and below wherever
John
2015/11/14 00:00:38
Done.
|
| + "Invalid mask for f32 modified immediates."); |
| + const float F32 = llvm::cast<ConstantFloat>(C)->getValue(); |
| + const uint32_t I32 = *reinterpret_cast<const uint32_t *>(&F32); |
| + if (I32 & ~AllowedBits) { |
| + // constant has disallowed bits. |
| + return false; |
| + } |
| + |
| + if ((I32 & bbbbb) != bbbbb && (I32 & bbbbb)) { |
| + // not all bbbbb bits are 0 or 1. |
| + return false; |
| + } |
| + |
| + if (((I32 & B) != 0) == ((I32 & bbbbb) != 0)) { |
| + // B ^ b = 0; |
| + return false; |
| + } |
| + |
| + *ModifiedImm = ((I32 & a) ? 0x80 : 0x00) | ((I32 & bbbbb) ? 0x40 : 0x00) | |
| + ((I32 & cdefgh) >> 19); |
| + return true; |
| + } |
| + case IceType_f64: { |
| + static constexpr uint32_t a = 0x80000000; |
| + static constexpr uint32_t B = 0x40000000; |
| + static constexpr uint32_t bbbbbbbb = 0x3FC00000; |
| + static constexpr uint32_t cdefgh = 0x003F0000; |
| + static constexpr uint32_t AllowedBits = a | B | bbbbbbbb | cdefgh; |
| + static_assert(AllowedBits == 0xFFFF0000, |
| + "Invalid mask for f64 modified immediates."); |
| + const double F64 = llvm::cast<ConstantDouble>(C)->getValue(); |
| + const uint64_t I64 = *reinterpret_cast<const uint64_t *>(&F64); |
| + if (I64 & 0xFFFFFFFF) { |
| + // constant has disallowed bits. |
| + return false; |
| + } |
| + const uint32_t I32 = I64 >> 32; |
| + |
| + if (I32 & ~AllowedBits) { |
| + // constant has disallowed bits. |
| + return false; |
| + } |
| + |
| + if ((I32 & bbbbbbbb) != bbbbbbbb && (I32 & bbbbbbbb)) { |
| + // not all bbbbb bits are 0 or 1. |
| + return false; |
| + } |
| + |
| + if (((I32 & B) != 0) == ((I32 & bbbbbbbb) != 0)) { |
| + // B ^ b = 0; |
| + return false; |
| + } |
| + |
| + *ModifiedImm = ((I32 & a) ? 0x80 : 0x00) | |
| + ((I32 & bbbbbbbb) ? 0x40 : 0x00) | ((I32 & cdefgh) >> 16); |
| + return true; |
| + } |
| + } |
| +} |
| + |
| +OperandARM32FlexFpZero::OperandARM32FlexFpZero(Cfg * /*Func*/, Type Ty) |
| + : OperandARM32Flex(kFlexFpZero, Ty) {} |
| + |
| OperandARM32FlexReg::OperandARM32FlexReg(Cfg *Func, Type Ty, Variable *Reg, |
| ShiftKind ShiftOp, Operand *ShiftAmt) |
| : OperandARM32Flex(kFlexReg, Ty), Reg(Reg), ShiftOp(ShiftOp), |
| @@ -557,15 +638,18 @@ template <> void InstARM32Tst::emitIAS(const Cfg *Func) const { |
| emitUsingTextFixup(Func); |
| } |
| -InstARM32Vcmp::InstARM32Vcmp(Cfg *Func, Variable *Src0, Variable *Src1, |
| +InstARM32Vcmp::InstARM32Vcmp(Cfg *Func, Variable *Src0, Operand *Src1, |
| CondARM32::Cond Predicate) |
| : InstARM32Pred(Func, InstARM32::Vcmp, 2, nullptr, Predicate) { |
| + HasSideEffects = true; |
| addSource(Src0); |
| addSource(Src1); |
| } |
| InstARM32Vmrs::InstARM32Vmrs(Cfg *Func, CondARM32::Cond Predicate) |
| - : InstARM32Pred(Func, InstARM32::Vmrs, 0, nullptr, Predicate) {} |
| + : InstARM32Pred(Func, InstARM32::Vmrs, 0, nullptr, Predicate) { |
| + HasSideEffects = true; |
| +} |
| InstARM32Vabs::InstARM32Vabs(Cfg *Func, Variable *Dest, Variable *Src, |
| CondARM32::Cond Predicate) |
| @@ -605,6 +689,7 @@ template <> const char *InstARM32Lsr::Opcode = "lsr"; |
| template <> const char *InstARM32Mul::Opcode = "mul"; |
| template <> const char *InstARM32Orr::Opcode = "orr"; |
| template <> const char *InstARM32Rsb::Opcode = "rsb"; |
| +template <> const char *InstARM32Rsc::Opcode = "rsc"; |
| template <> const char *InstARM32Sbc::Opcode = "sbc"; |
| template <> const char *InstARM32Sdiv::Opcode = "sdiv"; |
| template <> const char *InstARM32Sub::Opcode = "sub"; |
| @@ -1703,6 +1788,67 @@ void OperandARM32FlexImm::dump(const Cfg * /* Func */, Ostream &Str) const { |
| Str << "#(" << Imm << " ror 2*" << RotateAmt << ")"; |
| } |
| +namespace { |
| +static constexpr uint32_t a = 0x80; |
| +static constexpr uint32_t b = 0x40; |
| +static constexpr uint32_t cdefgh = 0x3F; |
| +static constexpr uint32_t AllowedBits = a | b | cdefgh; |
| +static_assert(AllowedBits == 0xFF, |
| + "Invalid mask for f32/f64 constant rematerialization."); |
| + |
| +// There's no loss in always returning the modified immediate as float. |
| +// TODO(jpp): returning a double causes problems when outputting the constants |
| +// for filetype=asm. Why? |
|
sehr
2015/11/13 21:56:29
How did you do the double version?
John
2015/11/14 00:00:38
almost the same things, except that the constant i
|
| +float materializeFloatImmediate(uint32_t ModifiedImm) { |
| + const uint32_t Ret = ((ModifiedImm & a) ? 0x80000000 : 0) | |
| + ((ModifiedImm & b) ? 0x3E000000 : 0x40000000) | |
| + ((ModifiedImm & cdefgh) << 19); |
| + return *reinterpret_cast<const float *>(&Ret); |
| +} |
| + |
| +} // end of anonymous namespace |
| + |
| +void OperandARM32FlexFpImm::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + switch (Ty) { |
| + default: |
| + llvm::report_fatal_error("Invalid flex fp imm type."); |
| + case IceType_f64: |
| + case IceType_f32: |
| + Str << "#" << materializeFloatImmediate(ModifiedImm) |
| + << " @ Modified: " << ModifiedImm; |
| + break; |
| + } |
| +} |
| + |
| +void OperandARM32FlexFpImm::dump(const Cfg * /*Func*/, Ostream &Str) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Str << "#" << materializeFloatImmediate(ModifiedImm) |
| + << InstARM32::getVecWidthString(Ty); |
| +} |
| + |
| +void OperandARM32FlexFpZero::emit(const Cfg *Func) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Ostream &Str = Func->getContext()->getStrEmit(); |
| + switch (Ty) { |
| + default: |
| + llvm::report_fatal_error("Invalid flex fp imm type."); |
| + case IceType_f64: |
| + case IceType_f32: |
| + Str << "#0.0"; |
| + } |
| +} |
| + |
| +void OperandARM32FlexFpZero::dump(const Cfg * /*Func*/, Ostream &Str) const { |
| + if (!BuildDefs::dump()) |
| + return; |
| + Str << "#0.0" << InstARM32::getVecWidthString(Ty); |
| +} |
| + |
| void OperandARM32FlexReg::emit(const Cfg *Func) const { |
| if (!BuildDefs::dump()) |
| return; |
| @@ -1743,6 +1889,7 @@ template class InstARM32ThreeAddrGPR<InstARM32::Lsr>; |
| template class InstARM32ThreeAddrGPR<InstARM32::Mul>; |
| template class InstARM32ThreeAddrGPR<InstARM32::Orr>; |
| template class InstARM32ThreeAddrGPR<InstARM32::Rsb>; |
| +template class InstARM32ThreeAddrGPR<InstARM32::Rsc>; |
| template class InstARM32ThreeAddrGPR<InstARM32::Sbc>; |
| template class InstARM32ThreeAddrGPR<InstARM32::Sdiv>; |
| template class InstARM32ThreeAddrGPR<InstARM32::Sub>; |