 Chromium Code Reviews
 Chromium Code Reviews Issue 1640913004:
  Subzero: Mips: Lower some i64 arithmetic instructions  (Closed) 
  Base URL: https://chromium.googlesource.com/native_client/pnacl-subzero.git@master
    
  
    Issue 1640913004:
  Subzero: Mips: Lower some i64 arithmetic instructions  (Closed) 
  Base URL: https://chromium.googlesource.com/native_client/pnacl-subzero.git@master| Index: src/IceTargetLoweringMIPS32.cpp | 
| diff --git a/src/IceTargetLoweringMIPS32.cpp b/src/IceTargetLoweringMIPS32.cpp | 
| index d8cd65c2973ac502ca2cd18f8c99e000754c1f23..e8fdb352c982b131fc33966eedcacaa6d5d77425 100644 | 
| --- a/src/IceTargetLoweringMIPS32.cpp | 
| +++ b/src/IceTargetLoweringMIPS32.cpp | 
| @@ -571,13 +571,101 @@ void TargetMIPS32::lowerAlloca(const InstAlloca *Inst) { | 
| UnimplementedLoweringError(this, Inst); | 
| } | 
| +void TargetMIPS32::lowerInt64Arithmetic(const InstArithmetic *Inst, | 
| + Variable *Dest, Operand *Src0, | 
| + Operand *Src1) { | 
| + InstArithmetic::OpKind Op = Inst->getOp(); | 
| + switch (Op) { | 
| + case InstArithmetic::Add: | 
| + case InstArithmetic::And: | 
| + case InstArithmetic::Or: | 
| + case InstArithmetic::Sub: | 
| + case InstArithmetic::Xor: | 
| + break; | 
| + default: | 
| + UnimplementedLoweringError(this, Inst); | 
| + return; | 
| + } | 
| + auto *DestLo = llvm::cast<Variable>(loOperand(Dest)); | 
| + auto *DestHi = llvm::cast<Variable>(hiOperand(Dest)); | 
| + Variable *Src0LoR = legalizeToReg(loOperand(Src0)); | 
| + Variable *Src1LoR = legalizeToReg(loOperand(Src1)); | 
| + Variable *Src0HiR = legalizeToReg(hiOperand(Src0)); | 
| + Variable *Src1HiR = legalizeToReg(hiOperand(Src1)); | 
| + | 
| + switch (Op) { | 
| + case InstArithmetic::_num: | 
| + llvm::report_fatal_error("Unknown arithmetic operator"); | 
| + return; | 
| + case InstArithmetic::Add: { | 
| + Variable *T_Carry = makeReg(IceType_i32); | 
| + Variable *T_Lo = makeReg(IceType_i32); | 
| + Variable *T_Hi = makeReg(IceType_i32); | 
| + Variable *T_Hi2 = makeReg(IceType_i32); | 
| + _addu(T_Lo, Src0LoR, Src1LoR); | 
| + _mov(DestLo, T_Lo); | 
| + _sltu(T_Carry, T_Lo, Src0LoR); | 
| + _addu(T_Hi, T_Carry, Src0HiR); | 
| + _addu(T_Hi2, Src1HiR, T_Hi); | 
| + _mov(DestHi, T_Hi2); | 
| + return; | 
| + } | 
| + case InstArithmetic::And: { | 
| + Variable *T_Lo = makeReg(IceType_i32); | 
| + Variable *T_Hi = makeReg(IceType_i32); | 
| + _and(T_Lo, Src0LoR, Src1LoR); | 
| + _mov(DestLo, T_Lo); | 
| + _and(T_Hi, Src0HiR, Src1HiR); | 
| + _mov(DestHi, T_Hi); | 
| + return; | 
| + } | 
| + case InstArithmetic::Sub: { | 
| + Variable *T_Borrow = makeReg(IceType_i32); | 
| + Variable *T_Lo = makeReg(IceType_i32); | 
| + Variable *T_Hi = makeReg(IceType_i32); | 
| + Variable *T_Hi2 = makeReg(IceType_i32); | 
| + _subu(T_Lo, Src0LoR, Src1LoR); | 
| + _mov(DestLo, T_Lo); | 
| + _sltu(T_Borrow, Src0LoR, Src1LoR); | 
| + _addu(T_Hi, T_Borrow, Src1HiR); | 
| + _subu(T_Hi2, Src0HiR, T_Hi); | 
| + _mov(DestHi, T_Hi2); | 
| + return; | 
| + } | 
| + case InstArithmetic::Or: { | 
| + Variable *T_Lo = makeReg(IceType_i32); | 
| + Variable *T_Hi = makeReg(IceType_i32); | 
| + _or(T_Lo, Src0LoR, Src1LoR); | 
| + _mov(DestLo, T_Lo); | 
| + _or(T_Hi, Src0HiR, Src1HiR); | 
| + _mov(DestHi, T_Hi); | 
| + return; | 
| + } | 
| + case InstArithmetic::Xor: { | 
| + Variable *T_Lo = makeReg(IceType_i32); | 
| + Variable *T_Hi = makeReg(IceType_i32); | 
| + _xor(T_Lo, Src0LoR, Src1LoR); | 
| + _mov(DestLo, T_Lo); | 
| + _xor(T_Hi, Src0HiR, Src1HiR); | 
| + _mov(DestHi, T_Hi); | 
| + return; | 
| + } | 
| + default: | 
| + UnimplementedLoweringError(this, Inst); | 
| + return; | 
| + } | 
| +} | 
| + | 
| void TargetMIPS32::lowerArithmetic(const InstArithmetic *Inst) { | 
| Variable *Dest = Inst->getDest(); | 
| // We need to signal all the UnimplementedLoweringError errors before any | 
| // legalization into new variables, otherwise Om1 register allocation may fail | 
| // when it sees variables that are defined but not used. | 
| - if (Dest->getType() == IceType_i64) { | 
| - UnimplementedLoweringError(this, Inst); | 
| + Type DestTy = Dest->getType(); | 
| + Operand *Src0 = legalizeUndef(Inst->getSrc(0)); | 
| + Operand *Src1 = legalizeUndef(Inst->getSrc(1)); | 
| + if (DestTy == IceType_i64) { | 
| + lowerInt64Arithmetic(Inst, Inst->getDest(), Src0, Src1); | 
| return; | 
| } | 
| if (isVectorType(Dest->getType())) { | 
| @@ -606,8 +694,6 @@ void TargetMIPS32::lowerArithmetic(const InstArithmetic *Inst) { | 
| // At this point Dest->getType() is non-i64 scalar | 
| Variable *T = makeReg(Dest->getType()); | 
| - Operand *Src0 = legalizeUndef(Inst->getSrc(0)); | 
| - Operand *Src1 = legalizeUndef(Inst->getSrc(1)); | 
| Variable *Src0R = legalizeToReg(Src0); | 
| Variable *Src1R = legalizeToReg(Src1); | 
| @@ -664,6 +750,7 @@ void TargetMIPS32::lowerArithmetic(const InstArithmetic *Inst) { | 
| case InstArithmetic::Frem: | 
| break; | 
| } | 
| + UnimplementedLoweringError(this, Inst); | 
| } | 
| void TargetMIPS32::lowerAssign(const InstAssign *Inst) { | 
| @@ -708,8 +795,93 @@ void TargetMIPS32::lowerBr(const InstBr *Inst) { | 
| UnimplementedLoweringError(this, Inst); | 
| } | 
| -void TargetMIPS32::lowerCall(const InstCall *Inst) { | 
| - UnimplementedLoweringError(this, Inst); | 
| +void TargetMIPS32::lowerCall(const InstCall *Instr) { | 
| + // TODO(rkotler): assign arguments to registers and stack. Also reserve stack. | 
| + if (Instr->getNumArgs()) { | 
| + UnimplementedLoweringError(this, Instr); | 
| + return; | 
| + } | 
| + // Generate the call instruction. Assign its result to a temporary with high | 
| + // register allocation weight. | 
| + Variable *Dest = Instr->getDest(); | 
| + // ReturnReg doubles as ReturnRegLo as necessary. | 
| + Variable *ReturnReg = nullptr; | 
| + Variable *ReturnRegHi = nullptr; | 
| + if (Dest) { | 
| + switch (Dest->getType()) { | 
| + case IceType_NUM: | 
| + llvm_unreachable("Invalid Call dest type"); | 
| + return; | 
| + case IceType_void: | 
| + break; | 
| + case IceType_i1: | 
| + case IceType_i8: | 
| + case IceType_i16: | 
| + case IceType_i32: | 
| + ReturnReg = makeReg(Dest->getType(), RegMIPS32::Reg_V0); | 
| + break; | 
| + case IceType_i64: | 
| + ReturnReg = makeReg(IceType_i32, RegMIPS32::Reg_V0); | 
| + ReturnRegHi = makeReg(IceType_i32, RegMIPS32::Reg_V1); | 
| + break; | 
| + case IceType_f32: | 
| + case IceType_f64: | 
| + UnimplementedLoweringError(this, Instr); | 
| + return; | 
| + case IceType_v4i1: | 
| + case IceType_v8i1: | 
| + case IceType_v16i1: | 
| + case IceType_v16i8: | 
| + case IceType_v8i16: | 
| + case IceType_v4i32: | 
| + case IceType_v4f32: | 
| + UnimplementedLoweringError(this, Instr); | 
| + return; | 
| + } | 
| + } | 
| + Operand *CallTarget = Instr->getCallTarget(); | 
| + // Allow ConstantRelocatable to be left alone as a direct call, | 
| + // but force other constants like ConstantInteger32 to be in | 
| + // a register and make it an indirect call. | 
| + if (!llvm::isa<ConstantRelocatable>(CallTarget)) { | 
| + CallTarget = legalize(CallTarget, Legal_Reg); | 
| + } | 
| + Inst *NewCall = InstMIPS32Call::create(Func, ReturnReg, CallTarget); | 
| + Context.insert(NewCall); | 
| + if (ReturnRegHi) | 
| + Context.insert(InstFakeDef::create(Func, ReturnRegHi)); | 
| + // Insert a register-kill pseudo instruction. | 
| + Context.insert(InstFakeKill::create(Func, NewCall)); | 
| + // Generate a FakeUse to keep the call live if necessary. | 
| + if (Instr->hasSideEffects() && ReturnReg) { | 
| + Inst *FakeUse = InstFakeUse::create(Func, ReturnReg); | 
| 
John
2016/02/01 04:29:32
You could have done
Context.insert<InstFakeDef>(F
 
rkotlerimgtec
2016/02/01 21:11:09
Done.
 | 
| + Context.insert(FakeUse); | 
| + } | 
| + if (Dest == nullptr) | 
| + return; | 
| + | 
| + // Assign the result of the call to Dest. | 
| + if (ReturnReg) { | 
| + if (ReturnRegHi) { | 
| + assert(Dest->getType() == IceType_i64); | 
| + auto *Dest64On32 = llvm::cast<Variable64On32>(Dest); | 
| + Variable *DestLo = Dest64On32->getLo(); | 
| + Variable *DestHi = Dest64On32->getHi(); | 
| + _mov(DestLo, ReturnReg); | 
| + _mov(DestHi, ReturnRegHi); | 
| + } else { | 
| + assert(Dest->getType() == IceType_i32 || Dest->getType() == IceType_i16 || | 
| + Dest->getType() == IceType_i8 || Dest->getType() == IceType_i1 || | 
| + isVectorType(Dest->getType())); | 
| + if (isFloatingType(Dest->getType()) || isVectorType(Dest->getType())) { | 
| + UnimplementedLoweringError(this, Instr); | 
| + return; | 
| + } else { | 
| + _mov(Dest, ReturnReg); | 
| + } | 
| + } | 
| + } | 
| + UnimplementedLoweringError(this, Instr); | 
| 
John
2016/02/01 04:29:32
Do you really want to report an error here?
 
rkotlerimgtec
2016/02/01 21:11:08
Done.
 | 
| } | 
| void TargetMIPS32::lowerCast(const InstCast *Inst) { | 
| @@ -980,8 +1152,8 @@ void TargetMIPS32::prelowerPhis() { | 
| void TargetMIPS32::postLower() { | 
| if (Ctx->getFlags().getOptLevel() == Opt_m1) | 
| return; | 
| - // Find two-address non-SSA instructions where Dest==Src0, and set the | 
| - // IsDestRedefined flag to keep liveness analysis consistent. | 
| + // TODO(rkotler): Find two-address non-SSA instructions where Dest==Src0, | 
| + // and set the IsDestRedefined flag to keep liveness analysis consistent. | 
| 
John
2016/02/01 04:29:32
You're better off explicitly setting the bit durin
 
Jim Stichnoth
2016/02/01 04:57:50
What this TODO really means, I think, is to call T
 
rkotlerimgtec
2016/02/01 21:11:08
Yes. The intention is just to do what ARM does her
 | 
| UnimplementedError(Func->getContext()->getFlags()); | 
| } | 
| @@ -1087,7 +1259,9 @@ Operand *TargetMIPS32::legalize(Operand *From, LegalMask Allowed, | 
| else | 
| Reg = getPhysicalRegister(RegNum); | 
| if (isInt<16>(int32_t(Value))) { | 
| - _addiu(Reg, getPhysicalRegister(RegMIPS32::Reg_ZERO, Ty), Value); | 
| + Variable *Zero = getPhysicalRegister(RegMIPS32::Reg_ZERO, Ty); | 
| + Context.insert<InstFakeDef>(Zero); | 
| + _addiu(Reg, Zero, Value); | 
| } else { | 
| uint32_t UpperBits = (Value >> 16) & 0xFFFF; | 
| (void)UpperBits; |