Commit f977f715 by John Porto

Subzero. Implements the scalar bitcast operations for ARM32.

parent 8072bae1
...@@ -403,7 +403,6 @@ template <> const char *InstARM32Ldr::Opcode = "ldr"; ...@@ -403,7 +403,6 @@ template <> const char *InstARM32Ldr::Opcode = "ldr";
template <> const char *InstARM32Mov::Opcode = "mov"; template <> const char *InstARM32Mov::Opcode = "mov";
// FP // FP
template <> const char *InstARM32Vldr::Opcode = "vldr"; template <> const char *InstARM32Vldr::Opcode = "vldr";
template <> const char *InstARM32Vmov::Opcode = "vmov";
// Three-addr ops // Three-addr ops
template <> const char *InstARM32Adc::Opcode = "adc"; template <> const char *InstARM32Adc::Opcode = "adc";
template <> const char *InstARM32Add::Opcode = "add"; template <> const char *InstARM32Add::Opcode = "add";
...@@ -498,15 +497,56 @@ template <> void InstARM32Vldr::emitIAS(const Cfg *Func) const { ...@@ -498,15 +497,56 @@ template <> void InstARM32Vldr::emitIAS(const Cfg *Func) const {
llvm_unreachable("Not yet implemented"); llvm_unreachable("Not yet implemented");
} }
template <> void InstARM32Vmov::emit(const Cfg *Func) const { void InstARM32Vmov::emitMultiDestSingleSource(const Cfg *Func) const {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrEmit();
Variable *Dest0 = getDest();
Operand *Src0 = getSrc(0);
assert(Dest0->hasReg());
assert(Dest1->hasReg());
assert(!llvm::isa<OperandARM32Mem>(Src0));
Str << "\t"
<< "vmov"
<< "\t";
Dest0->emit(Func);
Str << ", ";
Dest1->emit(Func);
Str << ", ";
Src0->emit(Func);
}
void InstARM32Vmov::emitSingleDestMultiSource(const Cfg *Func) const {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrEmit();
Variable *Dest0 = getDest();
Operand *Src0 = getSrc(0);
Operand *Src1 = getSrc(1);
assert(Dest0->hasReg());
assert(!llvm::isa<OperandARM32Mem>(Src0));
assert(!llvm::isa<OperandARM32Mem>(Src1));
Str << "\t"
<< "vmov"
<< "\t";
Dest0->emit(Func);
Str << ", ";
Src0->emit(Func);
Str << ", ";
Src1->emit(Func);
}
void InstARM32Vmov::emitSingleDestSingleSource(const Cfg *Func) const {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
assert(CondARM32::AL == getPredicate());
Ostream &Str = Func->getContext()->getStrEmit(); Ostream &Str = Func->getContext()->getStrEmit();
assert(getSrcSize() == 1);
Variable *Dest = getDest(); Variable *Dest = getDest();
if (Dest->hasReg()) { if (Dest->hasReg()) {
IceString ActualOpcode = Opcode; IceString ActualOpcode = "vmov";
Operand *Src0 = getSrc(0); Operand *Src0 = getSrc(0);
if (const auto *Src0V = llvm::dyn_cast<Variable>(Src0)) { if (const auto *Src0V = llvm::dyn_cast<Variable>(Src0)) {
if (!Src0V->hasReg()) { if (!Src0V->hasReg()) {
...@@ -532,12 +572,41 @@ template <> void InstARM32Vmov::emit(const Cfg *Func) const { ...@@ -532,12 +572,41 @@ template <> void InstARM32Vmov::emit(const Cfg *Func) const {
} }
} }
template <> void InstARM32Vmov::emitIAS(const Cfg *Func) const { void InstARM32Vmov::emit(const Cfg *Func) const {
if (!BuildDefs::dump())
return;
assert(CondARM32::AL == getPredicate());
assert(isMultiDest() + isMultiSource() <= 1 && "Invalid vmov type.");
if (isMultiDest()) {
emitMultiDestSingleSource(Func);
return;
}
if (isMultiSource()) {
emitSingleDestMultiSource(Func);
return;
}
emitSingleDestSingleSource(Func);
}
void InstARM32Vmov::emitIAS(const Cfg *Func) const {
assert(getSrcSize() == 1); assert(getSrcSize() == 1);
(void)Func; (void)Func;
llvm_unreachable("Not yet implemented"); llvm_unreachable("Not yet implemented");
} }
void InstARM32Vmov::dump(const Cfg *Func) const {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrDump();
dumpOpcodePred(Str, "vmov", getDest()->getType());
Str << " ";
dumpDest(Func);
Str << ", ";
dumpSources(Func);
}
void InstARM32Br::emit(const Cfg *Func) const { void InstARM32Br::emit(const Cfg *Func) const {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
......
...@@ -785,7 +785,6 @@ using InstARM32Ldr = InstARM32Movlike<InstARM32::Ldr>; ...@@ -785,7 +785,6 @@ using InstARM32Ldr = InstARM32Movlike<InstARM32::Ldr>;
using InstARM32Mov = InstARM32Movlike<InstARM32::Mov>; using InstARM32Mov = InstARM32Movlike<InstARM32::Mov>;
/// Represents various vector mov instruction forms (simple single source, /// Represents various vector mov instruction forms (simple single source,
/// single dest forms only, not the 2 GPR <-> 1 D reg forms, etc.). /// single dest forms only, not the 2 GPR <-> 1 D reg forms, etc.).
using InstARM32Vmov = InstARM32Movlike<InstARM32::Vmov>;
using InstARM32Vldr = InstARM32Movlike<InstARM32::Vldr>; using InstARM32Vldr = InstARM32Movlike<InstARM32::Vldr>;
/// MovT leaves the bottom bits alone so dest is also a source. /// MovT leaves the bottom bits alone so dest is also a source.
/// This helps indicate that a previous MovW setting dest is not dead code. /// This helps indicate that a previous MovW setting dest is not dead code.
...@@ -1119,6 +1118,93 @@ private: ...@@ -1119,6 +1118,93 @@ private:
const VcvtVariant Variant; const VcvtVariant Variant;
}; };
/// Handles (some of) vmov's various formats.
class InstARM32Vmov final : public InstARM32Pred {
InstARM32Vmov() = delete;
InstARM32Vmov(const InstARM32Vmov &) = delete;
InstARM32Vmov &operator=(const InstARM32Vmov &) = delete;
public:
/// RegisterPair is used to group registers in
///
/// vmov D, (R, R)
///
/// and
///
/// vmov (R, R), D
struct RegisterPair {
explicit RegisterPair(Variable *V0, Variable *V1) : _0(V0), _1(V1) {
assert(V0->getType() == IceType_i32);
assert(V1->getType() == IceType_i32);
}
Variable *_0;
Variable *_1;
};
static InstARM32Vmov *create(Cfg *Func, Variable *Dest, Operand *Src,
CondARM32::Cond Predicate) {
return new (Func->allocate<InstARM32Vmov>())
InstARM32Vmov(Func, Dest, Src, Predicate);
}
static InstARM32Vmov *create(Cfg *Func, const RegisterPair &Dests,
Variable *Src, CondARM32::Cond Predicate) {
return new (Func->allocate<InstARM32Vmov>())
InstARM32Vmov(Func, Dests, Src, Predicate);
}
static InstARM32Vmov *create(Cfg *Func, Variable *Dest,
const RegisterPair &Srcs,
CondARM32::Cond Predicate) {
return new (Func->allocate<InstARM32Vmov>())
InstARM32Vmov(Func, Dest, Srcs, Predicate);
}
bool isRedundantAssign() const override {
return Dest1 == nullptr && getSrcSize() == 1 &&
checkForRedundantAssign(getDest(), getSrc(0));
}
bool isSimpleAssign() const override { return true; }
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) { return isClassof(Inst, Vmov); }
private:
InstARM32Vmov(Cfg *Func, Variable *Dest, Operand *Src,
CondARM32::Cond Predicate)
: InstARM32Pred(Func, InstARM32::Vmov, 1, Dest, Predicate) {
addSource(Src);
}
InstARM32Vmov(Cfg *Func, const RegisterPair &Dests, Variable *Src,
CondARM32::Cond Predicate)
: InstARM32Pred(Func, InstARM32::Vmov, 1, Dests._0, Predicate),
Dest1(Dests._1) {
addSource(Src);
}
InstARM32Vmov(Cfg *Func, Variable *Dest, const RegisterPair &Srcs,
CondARM32::Cond Predicate)
: InstARM32Pred(Func, InstARM32::Vmov, 2, Dest, Predicate) {
addSource(Srcs._0);
addSource(Srcs._1);
}
bool isMultiDest() const {
assert(getDest() != nullptr);
return Dest1 != nullptr;
}
bool isMultiSource() const {
assert(getSrcSize() >= 1);
return getSrcSize() > 1;
}
void emitMultiDestSingleSource(const Cfg *Func) const;
void emitSingleDestMultiSource(const Cfg *Func) const;
void emitSingleDestSingleSource(const Cfg *Func) const;
Variable *Dest1 = nullptr;
};
// Declare partial template specializations of emit() methods that // Declare partial template specializations of emit() methods that
// already have default implementations. Without this, there is the // already have default implementations. Without this, there is the
// possibility of ODR violations and link errors. // possibility of ODR violations and link errors.
...@@ -1128,7 +1214,6 @@ template <> void InstARM32Mov::emit(const Cfg *Func) const; ...@@ -1128,7 +1214,6 @@ template <> void InstARM32Mov::emit(const Cfg *Func) const;
template <> void InstARM32Movw::emit(const Cfg *Func) const; template <> void InstARM32Movw::emit(const Cfg *Func) const;
template <> void InstARM32Movt::emit(const Cfg *Func) const; template <> void InstARM32Movt::emit(const Cfg *Func) const;
template <> void InstARM32Vldr::emit(const Cfg *Func) const; template <> void InstARM32Vldr::emit(const Cfg *Func) const;
template <> void InstARM32Vmov::emit(const Cfg *Func) const;
} // end of namespace Ice } // end of namespace Ice
......
...@@ -2108,6 +2108,9 @@ void TargetARM32::lowerCast(const InstCast *Inst) { ...@@ -2108,6 +2108,9 @@ void TargetARM32::lowerCast(const InstCast *Inst) {
UnimplementedError(Func->getContext()->getFlags()); UnimplementedError(Func->getContext()->getFlags());
break; break;
} else if (Dest->getType() == IceType_i64) { } else if (Dest->getType() == IceType_i64) {
split64(Dest);
Context.insert(InstFakeDef::create(Func, Dest->getLo()));
Context.insert(InstFakeDef::create(Func, Dest->getHi()));
UnimplementedError(Func->getContext()->getFlags()); UnimplementedError(Func->getContext()->getFlags());
break; break;
} }
...@@ -2144,7 +2147,10 @@ void TargetARM32::lowerCast(const InstCast *Inst) { ...@@ -2144,7 +2147,10 @@ void TargetARM32::lowerCast(const InstCast *Inst) {
if (isVectorType(Dest->getType())) { if (isVectorType(Dest->getType())) {
UnimplementedError(Func->getContext()->getFlags()); UnimplementedError(Func->getContext()->getFlags());
break; break;
} else if (Src0->getType() == IceType_i64) { }
if (Src0->getType() == IceType_i64) {
// avoid cryptic liveness errors
Context.insert(InstFakeDef::create(Func, Dest));
UnimplementedError(Func->getContext()->getFlags()); UnimplementedError(Func->getContext()->getFlags());
break; break;
} }
...@@ -2178,8 +2184,78 @@ void TargetARM32::lowerCast(const InstCast *Inst) { ...@@ -2178,8 +2184,78 @@ void TargetARM32::lowerCast(const InstCast *Inst) {
lowerAssign(Assign); lowerAssign(Assign);
return; return;
} }
Type DestType = Dest->getType();
switch (DestType) {
case IceType_NUM:
case IceType_void:
llvm::report_fatal_error("Unexpected bitcast.");
case IceType_i1:
UnimplementedError(Func->getContext()->getFlags());
break;
case IceType_v4i1:
UnimplementedError(Func->getContext()->getFlags());
break;
case IceType_i8:
UnimplementedError(Func->getContext()->getFlags());
break;
case IceType_i16:
UnimplementedError(Func->getContext()->getFlags()); UnimplementedError(Func->getContext()->getFlags());
break; break;
case IceType_i32:
case IceType_f32: {
Variable *Src0R = legalizeToReg(Src0);
Variable *T = makeReg(DestType);
_vmov(T, Src0R);
lowerAssign(InstAssign::create(Func, Dest, T));
break;
}
case IceType_i64: {
// t0, t1 <- src0
// dest[31..0] = t0
// dest[63..32] = t1
assert(Src0->getType() == IceType_f64);
Variable *T0 = makeReg(IceType_i32);
Variable *T1 = makeReg(IceType_i32);
Variable *Src0R = legalizeToReg(Src0);
split64(Dest);
_vmov(InstARM32Vmov::RegisterPair(T0, T1), Src0R);
lowerAssign(InstAssign::create(Func, Dest->getLo(), T0));
lowerAssign(InstAssign::create(Func, Dest->getHi(), T1));
break;
}
case IceType_f64: {
// T0 <- lo(src)
// T1 <- hi(src)
// vmov T2, T0, T1
// Dest <- T2
assert(Src0->getType() == IceType_i64);
Variable *SrcLo = legalizeToReg(loOperand(Src0));
Variable *SrcHi = legalizeToReg(hiOperand(Src0));
Variable *T = makeReg(IceType_f64);
_vmov(T, InstARM32Vmov::RegisterPair(SrcLo, SrcHi));
lowerAssign(InstAssign::create(Func, Dest, T));
break;
}
case IceType_v8i1:
UnimplementedError(Func->getContext()->getFlags());
break;
case IceType_v16i1:
UnimplementedError(Func->getContext()->getFlags());
break;
case IceType_v8i16:
UnimplementedError(Func->getContext()->getFlags());
break;
case IceType_v16i8:
UnimplementedError(Func->getContext()->getFlags());
break;
case IceType_v4i32:
UnimplementedError(Func->getContext()->getFlags());
break;
case IceType_v4f32:
UnimplementedError(Func->getContext()->getFlags());
break;
}
break;
} }
} }
} }
......
...@@ -415,6 +415,19 @@ protected: ...@@ -415,6 +415,19 @@ protected:
constexpr CondARM32::Cond Pred = CondARM32::AL; constexpr CondARM32::Cond Pred = CondARM32::AL;
Context.insert(InstARM32Vmov::create(Func, Dest, Src0, Pred)); Context.insert(InstARM32Vmov::create(Func, Dest, Src0, Pred));
} }
// This represents the single source, multi dest variant.
void _vmov(InstARM32Vmov::RegisterPair Dests, Variable *Src0) {
constexpr CondARM32::Cond Pred = CondARM32::AL;
Context.insert(InstARM32Vmov::create(Func, Dests, Src0, Pred));
// The Vmov instruction created above does not define Dests._1. Therefore
// we add a Dest._1 = FakeDef pseudo instruction.
Context.insert(InstFakeDef::create(Func, Dests._1));
}
// This represents the multi source, single dest variant.
void _vmov(Variable *Dest, InstARM32Vmov::RegisterPair Srcs) {
constexpr CondARM32::Cond Pred = CondARM32::AL;
Context.insert(InstARM32Vmov::create(Func, Dest, Srcs, Pred));
}
void _vmul(Variable *Dest, Variable *Src0, Variable *Src1) { void _vmul(Variable *Dest, Variable *Src0, Variable *Src1) {
Context.insert(InstARM32Vmul::create(Func, Dest, Src0, Src1)); Context.insert(InstARM32Vmul::create(Func, Dest, Src0, Src1));
} }
......
...@@ -3,6 +3,16 @@ ...@@ -3,6 +3,16 @@
; RUN: %p2i --filetype=obj --disassemble -i %s --args -O2 | FileCheck %s ; RUN: %p2i --filetype=obj --disassemble -i %s --args -O2 | FileCheck %s
; RUN: %p2i --filetype=obj --disassemble -i %s --args -Om1 | FileCheck %s ; RUN: %p2i --filetype=obj --disassemble -i %s --args -Om1 | FileCheck %s
; RUN: %if --need=allow_dump --need=target_ARM32 --command %p2i --filetype=asm \
; RUN: --target arm32 -i %s --args -O2 --skip-unimplemented \
; RUN: | %if --need=allow_dump --need=target_ARM32 --command FileCheck %s \
; RUN: --check-prefix=ARM32
; RUN: %if --need=allow_dump --need=target_ARM32 --command %p2i --filetype=asm \
; RUN: --target arm32 -i %s --args -Om1 --skip-unimplemented \
; RUN: | %if --need=allow_dump --need=target_ARM32 --command FileCheck %s \
; RUN: --check-prefix=ARM32
define internal i32 @cast_f2i(float %f) { define internal i32 @cast_f2i(float %f) {
entry: entry:
%v0 = bitcast float %f to i32 %v0 = bitcast float %f to i32
...@@ -10,6 +20,8 @@ entry: ...@@ -10,6 +20,8 @@ entry:
} }
; CHECK-LABEL: cast_f2i ; CHECK-LABEL: cast_f2i
; CHECK: mov eax ; CHECK: mov eax
; ARM32-LABEL: cast_f2i
; ARM32: vmov r{{[0-9]+}}, s{{[0-9]+}}
define internal float @cast_i2f(i32 %i) { define internal float @cast_i2f(i32 %i) {
entry: entry:
...@@ -18,6 +30,8 @@ entry: ...@@ -18,6 +30,8 @@ entry:
} }
; CHECK-LABEL: cast_i2f ; CHECK-LABEL: cast_i2f
; CHECK: fld DWORD PTR ; CHECK: fld DWORD PTR
; ARM32-LABEL: cast_i2f
; ARM32: vmov s{{[0-9]+}}, r{{[0-9]+}}
define internal i64 @cast_d2ll(double %d) { define internal i64 @cast_d2ll(double %d) {
entry: entry:
...@@ -26,6 +40,8 @@ entry: ...@@ -26,6 +40,8 @@ entry:
} }
; CHECK-LABEL: cast_d2ll ; CHECK-LABEL: cast_d2ll
; CHECK: mov edx ; CHECK: mov edx
; ARM32-LABEL: cast_d2ll
; ARM32: vmov r{{[0-9]+}}, r{{[0-9]+}}, d{{[0-9]+}}
define internal i64 @cast_d2ll_const() { define internal i64 @cast_d2ll_const() {
entry: entry:
...@@ -35,6 +51,11 @@ entry: ...@@ -35,6 +51,11 @@ entry:
; CHECK-LABEL: cast_d2ll_const ; CHECK-LABEL: cast_d2ll_const
; CHECK: mov e{{..}},DWORD PTR ds:0x0 {{.*}} .L$double$0 ; CHECK: mov e{{..}},DWORD PTR ds:0x0 {{.*}} .L$double$0
; CHECK: mov e{{..}},DWORD PTR ds:0x4 {{.*}} .L$double$0 ; CHECK: mov e{{..}},DWORD PTR ds:0x4 {{.*}} .L$double$0
; ARM32-LABEL: cast_d2ll_const
; ARM32-DAG: movw [[ADDR:r[0-9]+]], #:lower16:.L$
; ARM32-DAG: movt [[ADDR]], #:upper16:.L$
; ARM32-DAG: vldr [[DREG:d[0-9]+]], {{\[}}[[ADDR]], #0{{\]}}
; ARM32: vmov r{{[0-9]+}}, r{{[0-9]+}}, [[DREG]]
define internal double @cast_ll2d(i64 %ll) { define internal double @cast_ll2d(i64 %ll) {
entry: entry:
...@@ -43,6 +64,8 @@ entry: ...@@ -43,6 +64,8 @@ entry:
} }
; CHECK-LABEL: cast_ll2d ; CHECK-LABEL: cast_ll2d
; CHECK: fld QWORD PTR ; CHECK: fld QWORD PTR
; ARM32-LABEL: cast_ll2d
; ARM32: vmov d{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}
define internal double @cast_ll2d_const() { define internal double @cast_ll2d_const() {
entry: entry:
...@@ -53,3 +76,8 @@ entry: ...@@ -53,3 +76,8 @@ entry:
; CHECK: mov {{.*}},0x73ce2ff2 ; CHECK: mov {{.*}},0x73ce2ff2
; CHECK: mov {{.*}},0xb3a ; CHECK: mov {{.*}},0xb3a
; CHECK: fld QWORD PTR ; CHECK: fld QWORD PTR
; ARM32-LABEL: cast_ll2d_const
; ARM32-DAG: movw [[REG0:r[0-9]+]], #12274
; ARM32-DAG: movt [[REG0:r[0-9]+]], #29646
; ARM32-DAG: movw [[REG1:r[0-9]+]], #2874
; ARM32: vmov d{{[0-9]+}}, [[REG0]], [[REG1]]
...@@ -7,8 +7,14 @@ ...@@ -7,8 +7,14 @@
; RUN: %p2i --filetype=obj --disassemble -i %s --args -Om1 | FileCheck %s ; RUN: %p2i --filetype=obj --disassemble -i %s --args -Om1 | FileCheck %s
; RUN: %if --need=allow_dump --need=target_ARM32 --command %p2i --filetype=asm \ ; RUN: %if --need=allow_dump --need=target_ARM32 --command %p2i --filetype=asm \
; RUN: --target arm32 -i %s --args -O2 --skip-unimplemented \
; RUN: | %if --need=allow_dump --need=target_ARM32 --command FileCheck %s \
; RUN: --check-prefix=ARM32
; RUN: %if --need=allow_dump --need=target_ARM32 --command %p2i --filetype=asm \
; RUN: --target arm32 -i %s --args -Om1 --skip-unimplemented \ ; RUN: --target arm32 -i %s --args -Om1 --skip-unimplemented \
; RUN: | %if --need=target_ARM32 --command FileCheck %s --check-prefix=ARM32 ; RUN: | %if --need=allow_dump --need=target_ARM32 --command FileCheck %s \
; RUN: --check-prefix=ARM32
define internal float @fptrunc(double %a) { define internal float @fptrunc(double %a) {
entry: entry:
...@@ -554,8 +560,7 @@ entry: ...@@ -554,8 +560,7 @@ entry:
; CHECK-LABEL: int32BitcastToFloat ; CHECK-LABEL: int32BitcastToFloat
; CHECK: mov ; CHECK: mov
; ARM32-LABEL: int32BitcastToFloat ; ARM32-LABEL: int32BitcastToFloat
; TODO(jpp): implement this test. ; ARM32: vmov s{{[0-9]+}}, r{{[0-9]+}}
define internal float @int32BitcastToFloatConst() { define internal float @int32BitcastToFloatConst() {
entry: entry:
%conv = bitcast i32 8675309 to float %conv = bitcast i32 8675309 to float
...@@ -564,7 +569,9 @@ entry: ...@@ -564,7 +569,9 @@ entry:
; CHECK-LABEL: int32BitcastToFloatConst ; CHECK-LABEL: int32BitcastToFloatConst
; CHECK: mov ; CHECK: mov
; ARM32-LABEL: int32BitcastToFloatConst ; ARM32-LABEL: int32BitcastToFloatConst
; TODO(jpp): implement this test. ; ARM32-DAG: movw [[REG:r[0-9]+]], #24557
; ARM32-DAG: movt [[REG]], #132
; ARM32: vmov s{{[0-9]+}}, [[REG]]
define internal double @int64BitcastToDouble(i64 %a) { define internal double @int64BitcastToDouble(i64 %a) {
entry: entry:
...@@ -574,7 +581,7 @@ entry: ...@@ -574,7 +581,7 @@ entry:
; CHECK-LABEL: int64BitcastToDouble ; CHECK-LABEL: int64BitcastToDouble
; CHECK: mov ; CHECK: mov
; ARM32-LABEL: int64BitcastToDouble ; ARM32-LABEL: int64BitcastToDouble
; TODO(jpp): implement this test. ; ARM32: vmov d{{[0-9]+}}, r{{[0-9]+}}, r{{[0-9]+}}
define internal double @int64BitcastToDoubleConst() { define internal double @int64BitcastToDoubleConst() {
entry: entry:
...@@ -584,5 +591,7 @@ entry: ...@@ -584,5 +591,7 @@ entry:
; CHECK-LABEL: int64BitcastToDoubleConst ; CHECK-LABEL: int64BitcastToDoubleConst
; CHECK: mov ; CHECK: mov
; ARM32-LABEL: int64BitcastToDoubleConst ; ARM32-LABEL: int64BitcastToDoubleConst
; TODO(jpp): implement this test. ; ARM32-DAG: movw [[REG0:r[0-9]+]], #57336
; ARM32-DAG: movt [[REG0]], #137
; ARM32-DAG: movw [[REG1:r[0-9]+]], #0
; ARM32-DAG: vmov d{{[0-9]+}}, [[REG0]], [[REG1]]
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