| Index: src/IceTargetLoweringMIPS32.cpp
|
| diff --git a/src/IceTargetLoweringMIPS32.cpp b/src/IceTargetLoweringMIPS32.cpp
|
| index 7daf582a30b04d6adf276fff89c4623c406f9495..2522a1789f4087588d987b013971fef8af96d385 100644
|
| --- a/src/IceTargetLoweringMIPS32.cpp
|
| +++ b/src/IceTargetLoweringMIPS32.cpp
|
| @@ -240,6 +240,14 @@ uint32_t TargetMIPS32::getCallStackArgumentsSizeBytes(const InstCall *Call) {
|
| return applyStackAlignment(OutArgsSizeBytes);
|
| }
|
|
|
| +namespace {
|
| +inline uint64_t getConstantMemoryOrder(Operand *Opnd) {
|
| + if (auto *Integer = llvm::dyn_cast<ConstantInteger32>(Opnd))
|
| + return Integer->getValue();
|
| + return Intrinsics::MemoryOrderInvalid;
|
| +}
|
| +}
|
| +
|
| void TargetMIPS32::genTargetHelperCallFor(Inst *Instr) {
|
| constexpr bool NoTailCall = false;
|
| constexpr bool IsTargetHelperCall = true;
|
| @@ -1053,7 +1061,7 @@ bool TargetMIPS32::CallingConv::argInReg(Type Ty, uint32_t ArgNo,
|
| }
|
| return argInGPR(Ty, Reg);
|
| }
|
| - UnimplementedError(getFlags());
|
| + llvm::report_fatal_error("argInReg: Invalid type.");
|
| return false;
|
| }
|
|
|
| @@ -1062,7 +1070,7 @@ bool TargetMIPS32::CallingConv::argInGPR(Type Ty, RegNumT *Reg) {
|
|
|
| switch (Ty) {
|
| default: {
|
| - UnimplementedError(getFlags());
|
| + llvm::report_fatal_error("argInGPR: Invalid type.");
|
| return false;
|
| } break;
|
| case IceType_v4i1:
|
| @@ -1147,7 +1155,7 @@ bool TargetMIPS32::CallingConv::argInVFP(Type Ty, RegNumT *Reg) {
|
|
|
| switch (Ty) {
|
| default: {
|
| - UnimplementedError(getFlags());
|
| + llvm::report_fatal_error("argInVFP: Invalid type.");
|
| return false;
|
| } break;
|
| case IceType_f32: {
|
| @@ -2539,8 +2547,18 @@ void TargetMIPS32::lowerInt64Arithmetic(const InstArithmetic *Instr,
|
| _mov(DestLo, T1_Lo);
|
| return;
|
| }
|
| - default:
|
| - UnimplementedLoweringError(this, Instr);
|
| + case InstArithmetic::Fadd:
|
| + case InstArithmetic::Fsub:
|
| + case InstArithmetic::Fmul:
|
| + case InstArithmetic::Fdiv:
|
| + case InstArithmetic::Frem:
|
| + llvm::report_fatal_error("FP instruction with i64 type");
|
| + return;
|
| + case InstArithmetic::Udiv:
|
| + case InstArithmetic::Sdiv:
|
| + case InstArithmetic::Urem:
|
| + case InstArithmetic::Srem:
|
| + llvm::report_fatal_error("64-bit div and rem should have been prelowered");
|
| return;
|
| }
|
| }
|
| @@ -2784,7 +2802,7 @@ void TargetMIPS32::lowerArithmetic(const InstArithmetic *Instr) {
|
| llvm::report_fatal_error("frem should have been prelowered.");
|
| break;
|
| }
|
| - UnimplementedLoweringError(this, Instr);
|
| + llvm::report_fatal_error("Unknown arithmetic operator");
|
| }
|
|
|
| void TargetMIPS32::lowerAssign(const InstAssign *Instr) {
|
| @@ -3496,7 +3514,7 @@ void TargetMIPS32::lowerCast(const InstCast *Instr) {
|
| return;
|
| }
|
| }
|
| - UnimplementedLoweringError(this, Instr);
|
| + llvm::report_fatal_error("Destination is i64 in fp-to-i32");
|
| break;
|
| }
|
| case InstCast::Sitofp:
|
| @@ -3529,7 +3547,7 @@ void TargetMIPS32::lowerCast(const InstCast *Instr) {
|
| return;
|
| }
|
| }
|
| - UnimplementedLoweringError(this, Instr);
|
| + llvm::report_fatal_error("Source is i64 in i32-to-fp");
|
| break;
|
| }
|
| case InstCast::Bitcast: {
|
| @@ -3598,7 +3616,7 @@ void TargetMIPS32::lowerCast(const InstCast *Instr) {
|
| break;
|
| }
|
| default:
|
| - UnimplementedLoweringError(this, Instr);
|
| + llvm::report_fatal_error("Unexpected bitcast.");
|
| }
|
| break;
|
| }
|
| @@ -3690,7 +3708,7 @@ void TargetMIPS32::lowerFcmp(const InstFcmp *Instr) {
|
|
|
| switch (Cond) {
|
| default: {
|
| - UnimplementedLoweringError(this, Instr);
|
| + llvm::report_fatal_error("Unhandled fp comparison.");
|
| return;
|
| }
|
| case InstFcmp::False: {
|
| @@ -4235,36 +4253,430 @@ void TargetMIPS32::lowerInsertElement(const InstInsertElement *Instr) {
|
| llvm::report_fatal_error("InsertElement requires a constant index");
|
| }
|
|
|
| +void TargetMIPS32::createArithInst(Intrinsics::AtomicRMWOperation Operation,
|
| + Variable *Dest, Variable *Src0,
|
| + Variable *Src1) {
|
| + switch (Operation) {
|
| + default:
|
| + llvm::report_fatal_error("Unknown AtomicRMW operation");
|
| + case Intrinsics::AtomicExchange:
|
| + llvm::report_fatal_error("Can't handle Atomic xchg operation");
|
| + case Intrinsics::AtomicAdd:
|
| + _addu(Dest, Src0, Src1);
|
| + break;
|
| + case Intrinsics::AtomicAnd:
|
| + _and(Dest, Src0, Src1);
|
| + break;
|
| + case Intrinsics::AtomicSub:
|
| + _subu(Dest, Src0, Src1);
|
| + break;
|
| + case Intrinsics::AtomicOr:
|
| + _or(Dest, Src0, Src1);
|
| + break;
|
| + case Intrinsics::AtomicXor:
|
| + _xor(Dest, Src0, Src1);
|
| + break;
|
| + }
|
| +}
|
| +
|
| void TargetMIPS32::lowerIntrinsicCall(const InstIntrinsicCall *Instr) {
|
| Variable *Dest = Instr->getDest();
|
| Type DestTy = (Dest == nullptr) ? IceType_void : Dest->getType();
|
| - switch (Instr->getIntrinsicInfo().ID) {
|
| - case Intrinsics::AtomicCmpxchg: {
|
| - UnimplementedLoweringError(this, Instr);
|
| +
|
| + Intrinsics::IntrinsicID ID = Instr->getIntrinsicInfo().ID;
|
| + switch (ID) {
|
| + case Intrinsics::AtomicLoad: {
|
| + assert(isScalarIntegerType(DestTy));
|
| + // We require the memory address to be naturally aligned. Given that is the
|
| + // case, then normal loads are atomic.
|
| + if (!Intrinsics::isMemoryOrderValid(
|
| + ID, getConstantMemoryOrder(Instr->getArg(1)))) {
|
| + Func->setError("Unexpected memory ordering for AtomicLoad");
|
| + return;
|
| + }
|
| + if (DestTy == IceType_i64) {
|
| + auto *Base = legalizeToReg(Instr->getArg(0));
|
| + auto *AddrLo = OperandMIPS32Mem::create(
|
| + Func, IceType_i32, Base,
|
| + llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(0)));
|
| + auto *AddrHi = OperandMIPS32Mem::create(
|
| + Func, IceType_i32, Base,
|
| + llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(4)));
|
| + auto *T_Lo = makeReg(IceType_i32);
|
| + auto *T_Hi = makeReg(IceType_i32);
|
| + auto *Dest64 = llvm::cast<Variable64On32>(Dest);
|
| + lowerLoad(InstLoad::create(Func, T_Lo, AddrLo, IceType_i32));
|
| + lowerLoad(InstLoad::create(Func, T_Hi, AddrHi, IceType_i32));
|
| + _sync();
|
| + _mov(Dest64->getLo(), T_Lo);
|
| + _mov(Dest64->getHi(), T_Hi);
|
| + // Adding a fake-use of T to ensure the atomic load is not removed if Dest
|
| + // is unused.
|
| + Context.insert<InstFakeUse>(T_Lo);
|
| + Context.insert<InstFakeUse>(T_Hi);
|
| + } else {
|
| + auto *T = makeReg(DestTy);
|
| + lowerLoad(InstLoad::create(Func, T,
|
| + formMemoryOperand(Instr->getArg(0), DestTy)));
|
| + _sync();
|
| + _mov(Dest, T);
|
| + // Adding a fake-use of T to ensure the atomic load is not removed if Dest
|
| + // is unused.
|
| + Context.insert<InstFakeUse>(T);
|
| + }
|
| return;
|
| }
|
| - case Intrinsics::AtomicFence:
|
| - UnimplementedLoweringError(this, Instr);
|
| - return;
|
| - case Intrinsics::AtomicFenceAll:
|
| - // NOTE: FenceAll should prevent and load/store from being moved across the
|
| - // fence (both atomic and non-atomic). The InstMIPS32Mfence instruction is
|
| - // currently marked coarsely as "HasSideEffects".
|
| - UnimplementedLoweringError(this, Instr);
|
| + case Intrinsics::AtomicStore: {
|
| + // We require the memory address to be naturally aligned. Given that is the
|
| + // case, then normal stores are atomic.
|
| + if (!Intrinsics::isMemoryOrderValid(
|
| + ID, getConstantMemoryOrder(Instr->getArg(2)))) {
|
| + Func->setError("Unexpected memory ordering for AtomicStore");
|
| + return;
|
| + }
|
| + auto *Val = Instr->getArg(0);
|
| + auto Ty = Val->getType();
|
| + if (Ty == IceType_i64) {
|
| + Variable *ValHi, *ValLo;
|
| + _sync();
|
| + if (auto *C64 = llvm::dyn_cast<ConstantInteger64>(Val)) {
|
| + const uint64_t Value = C64->getValue();
|
| + uint64_t Upper32Bits = (Value >> INT32_BITS) & 0xFFFFFFFF;
|
| + uint64_t Lower32Bits = Value & 0xFFFFFFFF;
|
| + ValLo = legalizeToReg(Ctx->getConstantInt32(Lower32Bits));
|
| + ValHi = legalizeToReg(Ctx->getConstantInt32(Upper32Bits));
|
| + } else {
|
| + auto *Val64 = llvm::cast<Variable64On32>(Val);
|
| + ValLo = legalizeToReg(loOperand(Val64));
|
| + ValHi = legalizeToReg(hiOperand(Val64));
|
| + }
|
| +
|
| + auto *Base = legalizeToReg(Instr->getArg(1));
|
| + auto *AddrLo = OperandMIPS32Mem::create(
|
| + Func, IceType_i32, Base,
|
| + llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(0)));
|
| + auto *AddrHi = OperandMIPS32Mem::create(
|
| + Func, IceType_i32, Base,
|
| + llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(4)));
|
| + lowerStore(InstStore::create(Func, ValLo, AddrLo, IceType_i32));
|
| + lowerStore(InstStore::create(Func, ValHi, AddrHi, IceType_i32));
|
| + _sync();
|
| + } else {
|
| + _sync();
|
| + auto *Val = legalizeToReg(Instr->getArg(0));
|
| + lowerStore(InstStore::create(
|
| + Func, Val, formMemoryOperand(Instr->getArg(1), DestTy)));
|
| + _sync();
|
| + }
|
| return;
|
| - case Intrinsics::AtomicIsLockFree: {
|
| - UnimplementedLoweringError(this, Instr);
|
| + }
|
| + case Intrinsics::AtomicCmpxchg: {
|
| + assert(isScalarIntegerType(DestTy));
|
| + // We require the memory address to be naturally aligned. Given that is the
|
| + // case, then normal loads are atomic.
|
| + if (!Intrinsics::isMemoryOrderValid(
|
| + ID, getConstantMemoryOrder(Instr->getArg(3)),
|
| + getConstantMemoryOrder(Instr->getArg(4)))) {
|
| + Func->setError("Unexpected memory ordering for AtomicCmpxchg");
|
| + return;
|
| + }
|
| +
|
| + InstMIPS32Label *Exit = InstMIPS32Label::create(Func, this);
|
| + InstMIPS32Label *Retry = InstMIPS32Label::create(Func, this);
|
| + constexpr CfgNode *NoTarget = nullptr;
|
| + auto *New = Instr->getArg(2);
|
| + auto *Expected = Instr->getArg(1);
|
| + auto *ActualAddress = Instr->getArg(0);
|
| +
|
| + if (DestTy == IceType_i64) {
|
| + InstMIPS32Label *Retry1 = InstMIPS32Label::create(Func, this);
|
| + auto *T1 = I32Reg();
|
| + auto *T2 = I32Reg();
|
| + _sync();
|
| + Variable *ValHi, *ValLo, *ExpectedLo, *ExpectedHi;
|
| + if (llvm::isa<ConstantUndef>(Expected)) {
|
| + ExpectedLo = legalizeToReg(Ctx->getConstantZero(IceType_i32));
|
| + ExpectedHi = legalizeToReg(Ctx->getConstantZero(IceType_i32));
|
| + } else {
|
| + auto *Expected64 = llvm::cast<Variable64On32>(Expected);
|
| + ExpectedLo = legalizeToReg(loOperand(Expected64));
|
| + ExpectedHi = legalizeToReg(hiOperand(Expected64));
|
| + }
|
| + if (auto *C64 = llvm::dyn_cast<ConstantInteger64>(New)) {
|
| + const uint64_t Value = C64->getValue();
|
| + uint64_t Upper32Bits = (Value >> INT32_BITS) & 0xFFFFFFFF;
|
| + uint64_t Lower32Bits = Value & 0xFFFFFFFF;
|
| + ValLo = legalizeToReg(Ctx->getConstantInt32(Lower32Bits));
|
| + ValHi = legalizeToReg(Ctx->getConstantInt32(Upper32Bits));
|
| + } else {
|
| + auto *Val = llvm::cast<Variable64On32>(New);
|
| + ValLo = legalizeToReg(loOperand(Val));
|
| + ValHi = legalizeToReg(hiOperand(Val));
|
| + }
|
| + auto *Dest64 = llvm::cast<Variable64On32>(Dest);
|
| + auto *BaseR = legalizeToReg(ActualAddress);
|
| + auto *AddrLo = OperandMIPS32Mem::create(
|
| + Func, IceType_i32, BaseR,
|
| + llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(0)));
|
| + auto *AddrHi = OperandMIPS32Mem::create(
|
| + Func, IceType_i32, BaseR,
|
| + llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(4)));
|
| + Context.insert(Retry);
|
| + _ll(T1, AddrLo);
|
| + _br(NoTarget, NoTarget, T1, ExpectedLo, Exit, CondMIPS32::Cond::NE);
|
| + _sc(ValLo, AddrLo);
|
| + _br(NoTarget, NoTarget, ValLo, getZero(), Retry, CondMIPS32::Cond::EQ);
|
| + _mov(Dest64->getLo(), T1);
|
| + Context.insert(Retry1);
|
| + _ll(T2, AddrHi);
|
| + _br(NoTarget, NoTarget, T2, ExpectedHi, Exit, CondMIPS32::Cond::NE);
|
| + _sc(ValHi, AddrHi);
|
| + _br(NoTarget, NoTarget, ValHi, getZero(), Retry1, CondMIPS32::Cond::EQ);
|
| + _mov(Dest64->getHi(), T2);
|
| + Context.insert<InstFakeUse>(getZero());
|
| + Context.insert(Exit);
|
| + _sync();
|
| + } else if (DestTy == IceType_i8 || DestTy == IceType_i16) {
|
| + auto *NewR = legalizeToReg(New);
|
| + auto *ExpectedR = legalizeToReg(Expected);
|
| + auto *ActualAddressR = legalizeToReg(ActualAddress);
|
| + const uint32_t ShiftAmount =
|
| + (INT32_BITS - CHAR_BITS * typeWidthInBytes(DestTy));
|
| + const uint32_t Mask = (1 << (CHAR_BITS * typeWidthInBytes(DestTy))) - 1;
|
| + auto *RegAt = getPhysicalRegister(RegMIPS32::Reg_AT);
|
| + auto *T1 = I32Reg();
|
| + auto *T2 = I32Reg();
|
| + auto *T3 = I32Reg();
|
| + auto *T4 = I32Reg();
|
| + auto *T5 = I32Reg();
|
| + auto *T6 = I32Reg();
|
| + auto *T7 = I32Reg();
|
| + auto *T8 = I32Reg();
|
| + auto *T9 = I32Reg();
|
| + _sync();
|
| + _addiu(RegAt, getZero(), -4);
|
| + _and(T1, ActualAddressR, RegAt);
|
| + _andi(RegAt, ActualAddressR, 3);
|
| + _sll(T2, RegAt, 3);
|
| + _ori(RegAt, getZero(), Mask);
|
| + _sllv(T3, RegAt, T2);
|
| + _nor(T4, getZero(), T3);
|
| + _andi(RegAt, ExpectedR, Mask);
|
| + _sllv(T5, RegAt, T2);
|
| + _andi(RegAt, NewR, Mask);
|
| + _sllv(T6, RegAt, T2);
|
| + Context.insert(Retry);
|
| + _ll(T7, formMemoryOperand(T1, DestTy));
|
| + _and(T8, T7, T3);
|
| + _br(NoTarget, NoTarget, T8, T5, Exit, CondMIPS32::Cond::NE);
|
| + _and(RegAt, T7, T4);
|
| + _or(T9, RegAt, T6);
|
| + _sc(T9, formMemoryOperand(T1, DestTy));
|
| + _br(NoTarget, NoTarget, getZero(), T9, Retry, CondMIPS32::Cond::EQ);
|
| + Context.insert<InstFakeUse>(getZero());
|
| + Context.insert(Exit);
|
| + _srlv(RegAt, T8, T2);
|
| + _sll(RegAt, RegAt, ShiftAmount);
|
| + _sra(RegAt, RegAt, ShiftAmount);
|
| + _mov(Dest, RegAt);
|
| + _sync();
|
| + Context.insert<InstFakeUse>(ExpectedR);
|
| + Context.insert<InstFakeUse>(NewR);
|
| + } else {
|
| + auto *T1 = I32Reg();
|
| + auto *NewR = legalizeToReg(New);
|
| + auto *ExpectedR = legalizeToReg(Expected);
|
| + auto *ActualAddressR = legalizeToReg(ActualAddress);
|
| + _sync();
|
| + Context.insert(Retry);
|
| + _ll(T1, formMemoryOperand(ActualAddressR, DestTy));
|
| + _br(NoTarget, NoTarget, T1, ExpectedR, Exit, CondMIPS32::Cond::NE);
|
| + _sc(NewR, formMemoryOperand(ActualAddressR, DestTy));
|
| + _br(NoTarget, NoTarget, NewR, getZero(), Retry, CondMIPS32::Cond::EQ);
|
| + Context.insert<InstFakeUse>(getZero());
|
| + Context.insert(Exit);
|
| + _mov(Dest, T1);
|
| + _sync();
|
| + Context.insert<InstFakeUse>(ExpectedR);
|
| + Context.insert<InstFakeUse>(NewR);
|
| + }
|
| return;
|
| }
|
| - case Intrinsics::AtomicLoad: {
|
| - UnimplementedLoweringError(this, Instr);
|
| + case Intrinsics::AtomicRMW: {
|
| + assert(isScalarIntegerType(DestTy));
|
| + // We require the memory address to be naturally aligned. Given that is the
|
| + // case, then normal loads are atomic.
|
| + if (!Intrinsics::isMemoryOrderValid(
|
| + ID, getConstantMemoryOrder(Instr->getArg(3)))) {
|
| + Func->setError("Unexpected memory ordering for AtomicRMW");
|
| + return;
|
| + }
|
| +
|
| + constexpr CfgNode *NoTarget = nullptr;
|
| + InstMIPS32Label *Retry = InstMIPS32Label::create(Func, this);
|
| + auto Operation = static_cast<Intrinsics::AtomicRMWOperation>(
|
| + llvm::cast<ConstantInteger32>(Instr->getArg(0))->getValue());
|
| + auto *New = Instr->getArg(2);
|
| + auto *ActualAddress = Instr->getArg(1);
|
| +
|
| + if (DestTy == IceType_i64) {
|
| + InstMIPS32Label *Retry1 = InstMIPS32Label::create(Func, this);
|
| + _sync();
|
| + Variable *ValHi, *ValLo;
|
| + if (auto *C64 = llvm::dyn_cast<ConstantInteger64>(New)) {
|
| + const uint64_t Value = C64->getValue();
|
| + uint64_t Upper32Bits = (Value >> INT32_BITS) & 0xFFFFFFFF;
|
| + uint64_t Lower32Bits = Value & 0xFFFFFFFF;
|
| + ValLo = legalizeToReg(Ctx->getConstantInt32(Lower32Bits));
|
| + ValHi = legalizeToReg(Ctx->getConstantInt32(Upper32Bits));
|
| + } else {
|
| + auto *Val = llvm::cast<Variable64On32>(New);
|
| + ValLo = legalizeToReg(loOperand(Val));
|
| + ValHi = legalizeToReg(hiOperand(Val));
|
| + }
|
| + auto *Dest64 = llvm::cast<Variable64On32>(Dest);
|
| + auto *BaseR = legalizeToReg(ActualAddress);
|
| + auto *AddrLo = OperandMIPS32Mem::create(
|
| + Func, IceType_i32, BaseR,
|
| + llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(0)));
|
| + auto *AddrHi = OperandMIPS32Mem::create(
|
| + Func, IceType_i32, BaseR,
|
| + llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(4)));
|
| + auto *RegAt = getPhysicalRegister(RegMIPS32::Reg_AT);
|
| + auto *T1 = I32Reg();
|
| + auto *T2 = I32Reg();
|
| + auto *T3 = I32Reg();
|
| + Context.insert(Retry);
|
| + _ll(T1, AddrLo);
|
| + if (Operation == Intrinsics::AtomicExchange) {
|
| + _mov(RegAt, ValLo);
|
| + } else if (Operation == Intrinsics::AtomicAdd) {
|
| + createArithInst(Operation, RegAt, T1, ValLo);
|
| + _sltu(T2, RegAt, T1);
|
| + } else if (Operation == Intrinsics::AtomicSub) {
|
| + createArithInst(Operation, RegAt, T1, ValLo);
|
| + _sltu(T2, T1, ValLo);
|
| + } else {
|
| + createArithInst(Operation, RegAt, T1, ValLo);
|
| + }
|
| + _sc(RegAt, AddrLo);
|
| + _br(NoTarget, NoTarget, RegAt, getZero(), Retry, CondMIPS32::Cond::EQ);
|
| + Context.insert<InstFakeUse>(getZero());
|
| + _mov(Dest64->getLo(), T1);
|
| + Context.insert(Retry1);
|
| + _ll(T3, AddrHi);
|
| + if (Operation == Intrinsics::AtomicAdd ||
|
| + Operation == Intrinsics::AtomicSub) {
|
| + _addu(RegAt, T2, ValHi);
|
| + createArithInst(Operation, RegAt, T3, RegAt);
|
| + } else if (Operation == Intrinsics::AtomicExchange) {
|
| + _mov(RegAt, ValHi);
|
| + } else {
|
| + createArithInst(Operation, RegAt, T3, ValHi);
|
| + }
|
| + _sc(RegAt, AddrHi);
|
| + _br(NoTarget, NoTarget, RegAt, getZero(), Retry1, CondMIPS32::Cond::EQ);
|
| + Context.insert<InstFakeUse>(getZero());
|
| + _mov(Dest64->getHi(), T3);
|
| + Context.insert<InstFakeUse>(ValLo);
|
| + Context.insert<InstFakeUse>(ValHi);
|
| + _sync();
|
| + } else if (DestTy == IceType_i8 || DestTy == IceType_i16) {
|
| + const uint32_t ShiftAmount =
|
| + INT32_BITS - (CHAR_BITS * typeWidthInBytes(DestTy));
|
| + const uint32_t Mask = (1 << (CHAR_BITS * typeWidthInBytes(DestTy))) - 1;
|
| + auto *NewR = legalizeToReg(New);
|
| + auto *ActualAddressR = legalizeToReg(ActualAddress);
|
| + auto *RegAt = getPhysicalRegister(RegMIPS32::Reg_AT);
|
| + auto *T1 = I32Reg();
|
| + auto *T2 = I32Reg();
|
| + auto *T3 = I32Reg();
|
| + auto *T4 = I32Reg();
|
| + auto *T5 = I32Reg();
|
| + auto *T6 = I32Reg();
|
| + auto *T7 = I32Reg();
|
| + _sync();
|
| + _addiu(RegAt, getZero(), -4);
|
| + _and(T1, ActualAddressR, RegAt);
|
| + _andi(RegAt, ActualAddressR, 3);
|
| + _sll(T2, RegAt, 3);
|
| + _ori(RegAt, getZero(), Mask);
|
| + _sllv(T3, RegAt, T2);
|
| + _nor(T4, getZero(), T3);
|
| + _sllv(T5, NewR, T2);
|
| + Context.insert(Retry);
|
| + _ll(T6, formMemoryOperand(T1, DestTy));
|
| + if (Operation != Intrinsics::AtomicExchange) {
|
| + createArithInst(Operation, RegAt, T6, T5);
|
| + _and(RegAt, RegAt, T3);
|
| + }
|
| + _and(T7, T6, T4);
|
| + if (Operation == Intrinsics::AtomicExchange) {
|
| + _or(RegAt, T7, T5);
|
| + } else {
|
| + _or(RegAt, T7, RegAt);
|
| + }
|
| + _sc(RegAt, formMemoryOperand(T1, DestTy));
|
| + _br(NoTarget, NoTarget, RegAt, getZero(), Retry, CondMIPS32::Cond::EQ);
|
| + Context.insert<InstFakeUse>(getZero());
|
| + _and(RegAt, T6, T3);
|
| + _srlv(RegAt, RegAt, T2);
|
| + _sll(RegAt, RegAt, ShiftAmount);
|
| + _sra(RegAt, RegAt, ShiftAmount);
|
| + _mov(Dest, RegAt);
|
| + _sync();
|
| + Context.insert<InstFakeUse>(NewR);
|
| + Context.insert<InstFakeUse>(Dest);
|
| + } else {
|
| + auto *T1 = I32Reg();
|
| + auto *T2 = I32Reg();
|
| + auto *NewR = legalizeToReg(New);
|
| + auto *ActualAddressR = legalizeToReg(ActualAddress);
|
| + _sync();
|
| + Context.insert(Retry);
|
| + _ll(T1, formMemoryOperand(ActualAddressR, DestTy));
|
| + if (Operation == Intrinsics::AtomicExchange) {
|
| + _mov(T2, NewR);
|
| + } else {
|
| + createArithInst(Operation, T2, T1, NewR);
|
| + }
|
| + _sc(T2, formMemoryOperand(ActualAddressR, DestTy));
|
| + _br(NoTarget, NoTarget, T2, getZero(), Retry, CondMIPS32::Cond::EQ);
|
| + Context.insert<InstFakeUse>(getZero());
|
| + _mov(Dest, T1);
|
| + _sync();
|
| + Context.insert<InstFakeUse>(NewR);
|
| + Context.insert<InstFakeUse>(Dest);
|
| + }
|
| return;
|
| }
|
| - case Intrinsics::AtomicRMW:
|
| - UnimplementedLoweringError(this, Instr);
|
| + case Intrinsics::AtomicFence:
|
| + case Intrinsics::AtomicFenceAll:
|
| + assert(Dest == nullptr);
|
| + _sync();
|
| return;
|
| - case Intrinsics::AtomicStore: {
|
| - UnimplementedLoweringError(this, Instr);
|
| + case Intrinsics::AtomicIsLockFree: {
|
| + Operand *ByteSize = Instr->getArg(0);
|
| + auto *CI = llvm::dyn_cast<ConstantInteger32>(ByteSize);
|
| + auto *T = I32Reg();
|
| + if (CI == nullptr) {
|
| + // The PNaCl ABI requires the byte size to be a compile-time constant.
|
| + Func->setError("AtomicIsLockFree byte size should be compile-time const");
|
| + return;
|
| + }
|
| + static constexpr int32_t NotLockFree = 0;
|
| + static constexpr int32_t LockFree = 1;
|
| + int32_t Result = NotLockFree;
|
| + switch (CI->getValue()) {
|
| + case 1:
|
| + case 2:
|
| + case 4:
|
| + case 8:
|
| + Result = LockFree;
|
| + break;
|
| + }
|
| + _addiu(T, getZero(), Result);
|
| + _mov(Dest, T);
|
| return;
|
| }
|
| case Intrinsics::Bswap: {
|
| @@ -4935,7 +5347,7 @@ void TargetMIPS32::lowerSelect(const InstSelect *Instr) {
|
| _mov(Dest, SrcFR);
|
| break;
|
| default:
|
| - UnimplementedLoweringError(this, Instr);
|
| + llvm::report_fatal_error("Select: Invalid type.");
|
| }
|
| }
|
|
|
| @@ -5297,7 +5709,7 @@ Operand *TargetMIPS32::legalize(Operand *From, LegalMask Allowed,
|
| // using a lui-ori instructions.
|
| Variable *Reg = makeReg(Ty, RegNum);
|
| if (isInt<16>(int32_t(Value))) {
|
| - Variable *Zero = getPhysicalRegister(RegMIPS32::Reg_ZERO, Ty);
|
| + Variable *Zero = makeReg(Ty, RegMIPS32::Reg_ZERO);
|
| Context.insert<InstFakeDef>(Zero);
|
| _addiu(Reg, Zero, Value);
|
| } else {
|
|
|