Commit c31e2ed7 by John Porto

Implements int2fp, fp2int, and fp2fp conversions for ARM32.

64-bit ints (and vectors) are future work. BUG= https://code.google.com/p/nativeclient/issues/detail?id=4076 R=kschimpf@google.com, stichnot@chromium.org Review URL: https://codereview.chromium.org/1330933002 .
parent 6ef79494
......@@ -377,6 +377,13 @@ InstARM32Umull::InstARM32Umull(Cfg *Func, Variable *DestLo, Variable *DestHi,
addSource(Src1);
}
InstARM32Vcvt::InstARM32Vcvt(Cfg *Func, Variable *Dest, Variable *Src,
VcvtVariant Variant, CondARM32::Cond Predicate)
: InstARM32Pred(Func, InstARM32::Vcvt, 1, Dest, Predicate),
Variant(Variant) {
addSource(Src);
}
// ======================== Dump routines ======================== //
// Two-addr ops
......@@ -909,6 +916,63 @@ void InstARM32Umull::dump(const Cfg *Func) const {
dumpSources(Func);
}
namespace {
const char *vcvtVariantSuffix(const InstARM32Vcvt::VcvtVariant Variant) {
switch (Variant) {
case InstARM32Vcvt::S2si:
return ".s32.f32";
case InstARM32Vcvt::S2ui:
return ".u32.f32";
case InstARM32Vcvt::Si2s:
return ".f32.s32";
case InstARM32Vcvt::Ui2s:
return ".f32.u32";
case InstARM32Vcvt::D2si:
return ".s32.f64";
case InstARM32Vcvt::D2ui:
return ".u32.f64";
case InstARM32Vcvt::Si2d:
return ".f64.s32";
case InstARM32Vcvt::Ui2d:
return ".f64.u32";
case InstARM32Vcvt::S2d:
return ".f64.f32";
case InstARM32Vcvt::D2s:
return ".f32.f64";
}
llvm::report_fatal_error("Invalid VcvtVariant enum.");
}
} // end of anonymous namespace
void InstARM32Vcvt::emit(const Cfg *Func) const {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrEmit();
assert(getSrcSize() == 1);
assert(getDest()->hasReg());
Str << "\t"
<< "vcvt" << getPredicate() << vcvtVariantSuffix(Variant) << "\t";
getDest()->emit(Func);
Str << ", ";
getSrc(0)->emit(Func);
}
void InstARM32Vcvt::emitIAS(const Cfg *Func) const {
assert(getSrcSize() == 1);
(void)Func;
llvm_unreachable("Not yet implemented");
}
void InstARM32Vcvt::dump(const Cfg *Func) const {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrDump();
dumpDest(Func);
Str << " = "
<< "vcvt" << getPredicate() << vcvtVariantSuffix(Variant) << " ";
dumpSources(Func);
}
void OperandARM32Mem::emit(const Cfg *Func) const {
if (!BuildDefs::dump())
return;
......
......@@ -322,6 +322,7 @@ public:
Umull,
Uxt,
Vadd,
Vcvt,
Vdiv,
Vldr,
Vmov,
......@@ -1093,6 +1094,31 @@ private:
Variable *DestHi;
};
/// Handles fp2int, int2fp, and fp2fp conversions.
class InstARM32Vcvt final : public InstARM32Pred {
InstARM32Vcvt() = delete;
InstARM32Vcvt(const InstARM32Vcvt &) = delete;
InstARM32Vcvt &operator=(const InstARM32Vcvt &) = delete;
public:
enum VcvtVariant { S2si, S2ui, Si2s, Ui2s, D2si, D2ui, Si2d, Ui2d, S2d, D2s };
static InstARM32Vcvt *create(Cfg *Func, Variable *Dest, Variable *Src,
VcvtVariant Variant, CondARM32::Cond Predicate) {
return new (Func->allocate<InstARM32Vcvt>())
InstARM32Vcvt(Func, Dest, Src, Variant, Predicate);
}
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, Vcvt); }
private:
InstARM32Vcvt(Cfg *Func, Variable *Dest, Variable *Src, VcvtVariant Variant,
CondARM32::Cond Predicate);
const VcvtVariant Variant;
};
// Declare partial template specializations of emit() methods that
// already have default implementations. Without this, there is the
// possibility of ODR violations and link errors.
......
......@@ -34,14 +34,17 @@ namespace Ice {
namespace {
void UnimplementedError(const ClFlags &Flags) {
if (!Flags.getSkipUnimplemented()) {
// Use llvm_unreachable instead of report_fatal_error, which gives better
// stack traces.
llvm_unreachable("Not yet implemented");
abort();
}
}
// UnimplementedError is defined as a macro so that we can get actual line
// numbers.
#define UnimplementedError(Flags) \
do { \
if (!static_cast<const ClFlags &>(Flags).getSkipUnimplemented()) { \
/* Use llvm_unreachable instead of report_fatal_error, which gives \
better stack traces. */ \
llvm_unreachable("Not yet implemented"); \
abort(); \
} \
} while (0)
// The following table summarizes the logic for lowering the icmp instruction
// for i32 and narrower types. Each icmp condition has a clear mapping to an
......@@ -2075,25 +2078,97 @@ void TargetARM32::lowerCast(const InstCast *Inst) {
break;
}
case InstCast::Fptrunc:
UnimplementedError(Func->getContext()->getFlags());
break;
case InstCast::Fpext: {
UnimplementedError(Func->getContext()->getFlags());
// fptrunc: dest.f32 = fptrunc src0.fp64
// fpext: dest.f64 = fptrunc src0.fp32
const bool IsTrunc = CastKind == InstCast::Fptrunc;
if (isVectorType(Dest->getType())) {
UnimplementedError(Func->getContext()->getFlags());
break;
}
assert(Dest->getType() == (IsTrunc ? IceType_f32 : IceType_f64));
assert(Src0->getType() == (IsTrunc ? IceType_f64 : IceType_f32));
Variable *Src0R = legalizeToReg(Src0);
Variable *T = makeReg(Dest->getType());
_vcvt(T, Src0R, IsTrunc ? InstARM32Vcvt::D2s : InstARM32Vcvt::S2d);
_mov(Dest, T);
break;
}
case InstCast::Fptosi:
UnimplementedError(Func->getContext()->getFlags());
// Add a fake def to keep liveness consistent in the meantime.
Context.insert(InstFakeDef::create(Func, Dest));
break;
case InstCast::Fptoui:
UnimplementedError(Func->getContext()->getFlags());
case InstCast::Fptoui: {
// fptosi:
// t1.fp = vcvt src0.fp
// t2.i32 = vmov t1.fp
// dest.int = conv t2.i32 @ Truncates the result if needed.
// fptoui:
// t1.fp = vcvt src0.fp
// t2.u32 = vmov t1.fp
// dest.uint = conv t2.u32 @ Truncates the result if needed.
if (isVectorType(Dest->getType())) {
UnimplementedError(Func->getContext()->getFlags());
break;
} else if (Dest->getType() == IceType_i64) {
UnimplementedError(Func->getContext()->getFlags());
break;
}
const bool DestIsSigned = CastKind == InstCast::Fptosi;
Variable *Src0R = legalizeToReg(Src0);
Variable *T_fp = makeReg(IceType_f32);
if (isFloat32Asserting32Or64(Src0->getType())) {
_vcvt(T_fp, Src0R,
DestIsSigned ? InstARM32Vcvt::S2si : InstARM32Vcvt::S2ui);
} else {
_vcvt(T_fp, Src0R,
DestIsSigned ? InstARM32Vcvt::D2si : InstARM32Vcvt::D2ui);
}
Variable *T = makeReg(IceType_i32);
_vmov(T, T_fp);
if (Dest->getType() != IceType_i32) {
Variable *T_1 = makeReg(Dest->getType());
lowerCast(InstCast::create(Func, InstCast::Trunc, T_1, T));
T = T_1;
}
_mov(Dest, T);
break;
}
case InstCast::Sitofp:
UnimplementedError(Func->getContext()->getFlags());
break;
case InstCast::Uitofp: {
UnimplementedError(Func->getContext()->getFlags());
// sitofp:
// t1.i32 = sext src.int @ sign-extends src0 if needed.
// t2.fp32 = vmov t1.i32
// t3.fp = vcvt.{fp}.s32 @ fp is either f32 or f64
// uitofp:
// t1.i32 = zext src.int @ zero-extends src0 if needed.
// t2.fp32 = vmov t1.i32
// t3.fp = vcvt.{fp}.s32 @ fp is either f32 or f64
if (isVectorType(Dest->getType())) {
UnimplementedError(Func->getContext()->getFlags());
break;
} else if (Src0->getType() == IceType_i64) {
UnimplementedError(Func->getContext()->getFlags());
break;
}
const bool SourceIsSigned = CastKind == InstCast::Sitofp;
if (Src0->getType() != IceType_i32) {
Variable *Src0R_32 = makeReg(IceType_i32);
lowerCast(InstCast::create(Func, SourceIsSigned ? InstCast::Sext
: InstCast::Zext,
Src0R_32, Src0));
Src0 = Src0R_32;
}
Variable *Src0R = legalizeToReg(Src0);
Variable *Src0R_f32 = makeReg(IceType_f32);
_vmov(Src0R_f32, Src0R);
Src0R = Src0R_f32;
Variable *T = makeReg(Dest->getType());
if (isFloat32Asserting32Or64(Dest->getType())) {
_vcvt(T, Src0R,
SourceIsSigned ? InstARM32Vcvt::Si2s : InstARM32Vcvt::Ui2s);
} else {
_vcvt(T, Src0R,
SourceIsSigned ? InstARM32Vcvt::Si2d : InstARM32Vcvt::Ui2d);
}
_mov(Dest, T);
break;
}
case InstCast::Bitcast: {
......
......@@ -389,6 +389,10 @@ protected:
void _vadd(Variable *Dest, Variable *Src0, Variable *Src1) {
Context.insert(InstARM32Vadd::create(Func, Dest, Src0, Src1));
}
void _vcvt(Variable *Dest, Variable *Src, InstARM32Vcvt::VcvtVariant Variant,
CondARM32::Cond Pred = CondARM32::AL) {
Context.insert(InstARM32Vcvt::create(Func, Dest, Src, Variant, Pred));
}
void _vdiv(Variable *Dest, Variable *Src0, Variable *Src1) {
Context.insert(InstARM32Vdiv::create(Func, Dest, Src0, Src1));
}
......
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