| Index: src/IceTargetLoweringARM32.cpp
|
| diff --git a/src/IceTargetLoweringARM32.cpp b/src/IceTargetLoweringARM32.cpp
|
| index 3fb5efc1e3caebbfe4ca21a752c74e77695984a6..d61d93cf0430b57ff316dd2ab95ce07b48f33acf 100644
|
| --- a/src/IceTargetLoweringARM32.cpp
|
| +++ b/src/IceTargetLoweringARM32.cpp
|
| @@ -87,40 +87,39 @@ CondARM32::Cond getIcmp32Mapping(InstIcmp::ICond Cond) {
|
| // instructions/operands that use the same enum key value. The tables are kept
|
| // separate to maintain a proper separation between abstraction layers. There
|
| // is a risk that the tables could get out of sync if enum values are reordered
|
| -// or if entries are added or deleted. The following dummy namespaces use
|
| +// or if entries are added or deleted. The following anonymous namespaces use
|
| // static_asserts to ensure everything is kept in sync.
|
|
|
| // Validate the enum values in ICMPARM32_TABLE.
|
| -namespace dummy1 {
|
| +namespace {
|
| // Define a temporary set of enum values based on low-level table entries.
|
| -enum _tmp_enum {
|
| -#define X(val, signed, swapped64, C_32, C1_64, C2_64) _tmp_##val,
|
| +enum _icmp_ll_enum {
|
| +#define X(val, signed, swapped64, C_32, C1_64, C2_64) _icmp_ll_##val,
|
| ICMPARM32_TABLE
|
| #undef X
|
| _num
|
| };
|
| // Define a set of constants based on high-level table entries.
|
| -#define X(tag, str) static const int _table1_##tag = InstIcmp::tag;
|
| +#define X(tag, str) static constexpr int _icmp_hl_##tag = InstIcmp::tag;
|
| ICEINSTICMP_TABLE
|
| #undef X
|
| // Define a set of constants based on low-level table entries, and ensure the
|
| // table entry keys are consistent.
|
| #define X(val, signed, swapped64, C_32, C1_64, C2_64) \
|
| - static const int _table2_##val = _tmp_##val; \
|
| static_assert( \
|
| - _table1_##val == _table2_##val, \
|
| - "Inconsistency between ICMPARM32_TABLE and ICEINSTICMP_TABLE");
|
| + _icmp_ll_##val == _icmp_hl_##val, \
|
| + "Inconsistency between ICMPARM32_TABLE and ICEINSTICMP_TABLE: " #val);
|
| ICMPARM32_TABLE
|
| #undef X
|
| // Repeat the static asserts with respect to the high-level table entries in
|
| // case the high-level table has extra entries.
|
| #define X(tag, str) \
|
| static_assert( \
|
| - _table1_##tag == _table2_##tag, \
|
| - "Inconsistency between ICMPARM32_TABLE and ICEINSTICMP_TABLE");
|
| + _icmp_hl_##tag == _icmp_ll_##tag, \
|
| + "Inconsistency between ICMPARM32_TABLE and ICEINSTICMP_TABLE: " #tag);
|
| ICEINSTICMP_TABLE
|
| #undef X
|
| -} // end of namespace dummy1
|
| +} // end of anonymous namespace
|
|
|
| // Stack alignment
|
| const uint32_t ARM32_STACK_ALIGNMENT_BYTES = 16;
|
| @@ -2229,9 +2228,76 @@ void TargetARM32::lowerExtractElement(const InstExtractElement *Inst) {
|
| UnimplementedError(Func->getContext()->getFlags());
|
| }
|
|
|
| +namespace {
|
| +// Validates FCMPARM32_TABLE's declaration w.r.t. InstFcmp::FCondition ordering
|
| +// (and naming).
|
| +enum {
|
| +#define X(val, CC0, CC1) _fcmp_ll_##val,
|
| + FCMPARM32_TABLE
|
| +#undef X
|
| + _fcmp_ll_NUM
|
| +};
|
| +
|
| +enum {
|
| +#define X(tag, str) _fcmp_hl_##tag = InstFcmp::tag,
|
| + ICEINSTFCMP_TABLE
|
| +#undef X
|
| + _fcmp_hl_NUM
|
| +};
|
| +
|
| +static_assert(_fcmp_hl_NUM == _fcmp_ll_NUM,
|
| + "Inconsistency between high-level and low-level fcmp tags.");
|
| +#define X(tag, str) \
|
| + static_assert( \
|
| + _fcmp_hl_##tag == _fcmp_ll_##tag, \
|
| + "Inconsistency between high-level and low-level fcmp tag " #tag);
|
| +ICEINSTFCMP_TABLE
|
| +#undef X
|
| +
|
| +struct {
|
| + CondARM32::Cond CC0;
|
| + CondARM32::Cond CC1;
|
| +} TableFcmp[] = {
|
| +#define X(val, CC0, CC1) \
|
| + { CondARM32::CC0, CondARM32::CC1 } \
|
| + ,
|
| + FCMPARM32_TABLE
|
| +#undef X
|
| +};
|
| +} // end of anonymous namespace
|
| +
|
| void TargetARM32::lowerFcmp(const InstFcmp *Inst) {
|
| - (void)Inst;
|
| - UnimplementedError(Func->getContext()->getFlags());
|
| + Variable *Dest = Inst->getDest();
|
| + if (isVectorType(Dest->getType())) {
|
| + UnimplementedError(Func->getContext()->getFlags());
|
| + return;
|
| + }
|
| +
|
| + Variable *Src0R = legalizeToReg(Inst->getSrc(0));
|
| + Variable *Src1R = legalizeToReg(Inst->getSrc(1));
|
| + Variable *T = makeReg(IceType_i32);
|
| + _vcmp(Src0R, Src1R);
|
| + _mov(T, Ctx->getConstantZero(IceType_i32));
|
| + _vmrs();
|
| + Operand *One = Ctx->getConstantInt32(1);
|
| + InstFcmp::FCond Condition = Inst->getCondition();
|
| + assert(Condition < llvm::array_lengthof(TableFcmp));
|
| + CondARM32::Cond CC0 = TableFcmp[Condition].CC0;
|
| + CondARM32::Cond CC1 = TableFcmp[Condition].CC1;
|
| + if (CC0 != CondARM32::kNone) {
|
| + _mov(T, One, CC0);
|
| + // If this mov is not a maybe mov, but an actual mov (i.e., CC0 == AL), we
|
| + // don't want to set_dest_nonkillable so that liveness + dead-code
|
| + // elimination will get rid of the previous assignment (i.e., T = 0) above.
|
| + if (CC0 != CondARM32::AL)
|
| + _set_dest_nonkillable();
|
| + }
|
| + if (CC1 != CondARM32::kNone) {
|
| + assert(CC0 != CondARM32::kNone);
|
| + assert(CC1 != CondARM32::AL);
|
| + _mov_nonkillable(T, One, CC1);
|
| + }
|
| + _mov(Dest, T);
|
| }
|
|
|
| void TargetARM32::lowerIcmp(const InstIcmp *Inst) {
|
| @@ -2695,16 +2761,12 @@ void TargetARM32::lowerSelect(const InstSelect *Inst) {
|
| UnimplementedError(Func->getContext()->getFlags());
|
| return;
|
| }
|
| - if (isFloatingType(DestTy)) {
|
| - UnimplementedError(Func->getContext()->getFlags());
|
| - return;
|
| - }
|
| // TODO(jvoung): handle folding opportunities.
|
| // cmp cond, #0; mov t, SrcF; mov_cond t, SrcT; mov dest, t
|
| Variable *CmpOpnd0 = legalizeToReg(Condition);
|
| Operand *CmpOpnd1 = Ctx->getConstantZero(IceType_i32);
|
| _cmp(CmpOpnd0, CmpOpnd1);
|
| - CondARM32::Cond Cond = CondARM32::NE;
|
| + static constexpr CondARM32::Cond Cond = CondARM32::NE;
|
| if (DestTy == IceType_i64) {
|
| SrcT = legalizeUndef(SrcT);
|
| SrcF = legalizeUndef(SrcF);
|
| @@ -2726,6 +2788,20 @@ void TargetARM32::lowerSelect(const InstSelect *Inst) {
|
| _mov(DestHi, THi);
|
| return;
|
| }
|
| +
|
| + if (isFloatingType(DestTy)) {
|
| + Variable *T = makeReg(DestTy);
|
| + SrcF = legalizeToReg(SrcF);
|
| + assert(DestTy == SrcF->getType());
|
| + _vmov(T, SrcF);
|
| + SrcT = legalizeToReg(SrcT);
|
| + assert(DestTy == SrcT->getType());
|
| + _vmov(T, SrcT, Cond);
|
| + _set_dest_nonkillable();
|
| + _vmov(Dest, T);
|
| + return;
|
| + }
|
| +
|
| Variable *T = nullptr;
|
| SrcF = legalize(SrcF, Legal_Reg | Legal_Flex);
|
| _mov(T, SrcF);
|
|
|