Index: src/IceTargetLoweringMIPS32.cpp |
diff --git a/src/IceTargetLoweringMIPS32.cpp b/src/IceTargetLoweringMIPS32.cpp |
index d8cd65c2973ac502ca2cd18f8c99e000754c1f23..189f634180755cef73a848230cb1045705407460 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); |
@@ -615,7 +701,7 @@ void TargetMIPS32::lowerArithmetic(const InstArithmetic *Inst) { |
case InstArithmetic::_num: |
break; |
case InstArithmetic::Add: |
- _add(T, Src0R, Src1R); |
+ _addu(T, Src0R, Src1R); |
_mov(Dest, T); |
return; |
case InstArithmetic::And: |
@@ -631,7 +717,7 @@ void TargetMIPS32::lowerArithmetic(const InstArithmetic *Inst) { |
_mov(Dest, T); |
return; |
case InstArithmetic::Sub: |
- _sub(T, Src0R, Src1R); |
+ _subu(T, Src0R, Src1R); |
_mov(Dest, T); |
return; |
case InstArithmetic::Mul: { |
@@ -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,91 @@ 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) { |
+ Context.insert<InstFakeDef>(ReturnReg); |
+ } |
+ 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); |
+ } |
+ } |
+ } |
} |
void TargetMIPS32::lowerCast(const InstCast *Inst) { |
@@ -980,8 +1150,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. |
UnimplementedError(Func->getContext()->getFlags()); |
} |
@@ -1087,7 +1257,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; |