Index: llvm/trunk/lib/Target/Mips/MipsFastISel.cpp =================================================================== --- llvm/trunk/lib/Target/Mips/MipsFastISel.cpp +++ llvm/trunk/lib/Target/Mips/MipsFastISel.cpp @@ -100,6 +100,7 @@ bool selectRet(const Instruction *I); bool selectTrunc(const Instruction *I); bool selectIntExt(const Instruction *I); + bool selectShift(const Instruction *I); // Utility helper routines. bool isTypeLegal(Type *Ty, MVT &VT); @@ -1386,6 +1387,81 @@ return Success ? DestReg : 0; } +bool MipsFastISel::selectShift(const Instruction *I) { + MVT RetVT; + + if (!isTypeSupported(I->getType(), RetVT)) + return false; + + unsigned ResultReg = createResultReg(&Mips::GPR32RegClass); + if (!ResultReg) + return false; + + unsigned Opcode = I->getOpcode(); + const Value *Op0 = I->getOperand(0); + unsigned Op0Reg = getRegForValue(Op0); + if (!Op0Reg) + return false; + + // If AShr or LShr, then we need to make sure the operand0 is sign extended. + if (Opcode == Instruction::AShr || Opcode == Instruction::LShr) { + unsigned TempReg = createResultReg(&Mips::GPR32RegClass); + if (!TempReg) + return false; + + MVT Op0MVT = TLI.getValueType(Op0->getType(), true).getSimpleVT(); + bool IsZExt = Opcode == Instruction::LShr; + if (!emitIntExt(Op0MVT, Op0Reg, MVT::i32, TempReg, IsZExt)) + return false; + + Op0Reg = TempReg; + } + + if (const auto *C = dyn_cast(I->getOperand(1))) { + uint64_t ShiftVal = C->getZExtValue(); + + switch (Opcode) { + default: + llvm_unreachable("Unexpected instruction."); + case Instruction::Shl: + Opcode = Mips::SLL; + break; + case Instruction::AShr: + Opcode = Mips::SRA; + break; + case Instruction::LShr: + Opcode = Mips::SRL; + break; + } + + emitInst(Opcode, ResultReg).addReg(Op0Reg).addImm(ShiftVal); + updateValueMap(I, ResultReg); + return true; + } + + unsigned Op1Reg = getRegForValue(I->getOperand(1)); + if (!Op1Reg) + return false; + + switch (Opcode) { + default: + llvm_unreachable("Unexpected instruction."); + case Instruction::Shl: + Opcode = Mips::SLLV; + break; + case Instruction::AShr: + Opcode = Mips::SRAV; + break; + case Instruction::LShr: + Opcode = Mips::SRLV; + break; + } + + emitInst(Opcode, ResultReg).addReg(Op0Reg).addReg(Op1Reg); + updateValueMap(I, ResultReg); + return true; +} + bool MipsFastISel::fastSelectInstruction(const Instruction *I) { if (!TargetSupported) return false; @@ -1396,6 +1472,10 @@ return selectLoad(I); case Instruction::Store: return selectStore(I); + case Instruction::Shl: + case Instruction::LShr: + case Instruction::AShr: + return selectShift(I); case Instruction::And: case Instruction::Or: case Instruction::Xor: Index: llvm/trunk/test/CodeGen/Mips/Fast-ISel/shftopm.ll =================================================================== --- llvm/trunk/test/CodeGen/Mips/Fast-ISel/shftopm.ll +++ llvm/trunk/test/CodeGen/Mips/Fast-ISel/shftopm.ll @@ -0,0 +1,122 @@ +; RUN: llc -march=mipsel -relocation-model=pic -O0 -mips-fast-isel \ +; RUN: -fast-isel-abort=1 -mcpu=mips32r2 < %s | FileCheck %s +; RUN: llc -march=mipsel -relocation-model=pic -O0 -mips-fast-isel \ +; RUN: -fast-isel-abort=1 -mcpu=mips32 < %s | FileCheck %s + +@s1 = global i16 -89, align 2 +@s2 = global i16 4, align 2 +@us1 = global i16 -503, align 2 +@us2 = global i16 5, align 2 +@s3 = common global i16 0, align 2 +@us3 = common global i16 0, align 2 + +define void @sll() { +entry: + %0 = load i16, i16* @s1, align 2 + %1 = load i16, i16* @s2, align 2 + %shl = shl i16 %0, %1 + store i16 %shl, i16* @s3, align 2 +; CHECK-LABEL: sll: +; CHECK: lui $[[REG_GPa:[0-9]+]], %hi(_gp_disp) +; CHECK-DAG: addiu $[[REG_GPb:[0-9]+]], $[[REG_GPa]], %lo(_gp_disp) +; CHECK-DAG: addu $[[REG_GP:[0-9]+]], $[[REG_GPb]], $25 +; CHECK-DAG: lw $[[S3_ADDR:[0-9]+]], %got(s3)($[[REG_GP]]) +; CHECK-DAG: lw $[[S2_ADDR:[0-9]+]], %got(s2)($[[REG_GP]]) +; CHECK-DAG: lw $[[S1_ADDR:[0-9]+]], %got(s1)($[[REG_GP]]) +; CHECK-DAG: lhu $[[S1:[0-9]+]], 0($[[S1_ADDR]]) +; CHECK-DAG: lhu $[[S2:[0-9]+]], 0($[[S2_ADDR]]) +; CHECK: sllv $[[RES:[0-9]+]], $[[S1]], $[[S2]] +; CHECK: sh $[[RES]], 0($[[S3_ADDR]]) + ret void +} + +define void @slli() { +entry: + %0 = load i16, i16* @s1, align 2 + %shl = shl i16 %0, 5 + store i16 %shl, i16* @s3, align 2 +; CHECK-LABEL: slli: +; CHECK: lui $[[REG_GPa:[0-9]+]], %hi(_gp_disp) +; CHECK-DAG: addiu $[[REG_GPb:[0-9]+]], $[[REG_GPa]], %lo(_gp_disp) +; CHECK-DAG: addu $[[REG_GP:[0-9]+]], $[[REG_GPb]], $25 +; CHECK-DAG: lw $[[S3_ADDR:[0-9]+]], %got(s3)($[[REG_GP]]) +; CHECK-DAG: lw $[[S1_ADDR:[0-9]+]], %got(s1)($[[REG_GP]]) +; CHECK-DAG: lhu $[[S1:[0-9]+]], 0($[[S1_ADDR]]) +; CHECK: sll $[[RES:[0-9]+]], $[[S1]], 5 +; CHECK: sh $[[RES]], 0($[[S3_ADDR]]) + ret void +} + +define void @srl() { +entry: + %0 = load i16, i16* @us1, align 2 + %1 = load i16, i16* @us2, align 2 + %shr = lshr i16 %0, %1 + store i16 %shr, i16* @us3, align 2 + ret void +; CHECK-LABEL: srl: +; CHECK: lui $[[REG_GPa:[0-9]+]], %hi(_gp_disp) +; CHECK-DAG: addiu $[[REG_GPb:[0-9]+]], $[[REG_GPa]], %lo(_gp_disp) +; CHECK-DAG: addu $[[REG_GP:[0-9]+]], $[[REG_GPb]], $25 +; CHECK-DAG: lw $[[US3_ADDR:[0-9]+]], %got(us3)($[[REG_GP]]) +; CHECK-DAG: lw $[[US2_ADDR:[0-9]+]], %got(us2)($[[REG_GP]]) +; CHECK-DAG: lw $[[US1_ADDR:[0-9]+]], %got(us1)($[[REG_GP]]) +; CHECK-DAG: lhu $[[US1:[0-9]+]], 0($[[US1_ADDR]]) +; CHECK-DAG: lhu $[[US2:[0-9]+]], 0($[[US2_ADDR]]) +; CHECK: srlv $[[RES:[0-9]+]], $[[US1]], $[[US2]] +; CHECK: sh $[[RES]], 0($[[S3_ADDR]]) +} + +define void @srli() { +entry: + %0 = load i16, i16* @us1, align 2 + %shr = lshr i16 %0, 4 + store i16 %shr, i16* @us3, align 2 +; CHECK-LABEL: srli: +; CHECK: lui $[[REG_GPa:[0-9]+]], %hi(_gp_disp) +; CHECK-DAG: addiu $[[REG_GPb:[0-9]+]], $[[REG_GPa]], %lo(_gp_disp) +; CHECK-DAG: addu $[[REG_GP:[0-9]+]], $[[REG_GPb]], $25 +; CHECK-DAG: lw $[[US3_ADDR:[0-9]+]], %got(us3)($[[REG_GP]]) +; CHECK-DAG: lw $[[US1_ADDR:[0-9]+]], %got(us1)($[[REG_GP]]) +; CHECK-DAG: lhu $[[US1:[0-9]+]], 0($[[US1_ADDR]]) +; CHECK: srl $[[RES:[0-9]+]], $[[US1]], 4 +; CHECK: sh $[[RES]], 0($[[S3_ADDR]]) + ret void +} + +define void @sra() { +entry: + %0 = load i16, i16* @s1, align 2 + %1 = load i16, i16* @s2, align 2 + %shr = ashr i16 %0, %1 + store i16 %shr, i16* @s3, align 2 +; CHECK-LABEL: sra: +; CHECK: lui $[[REG_GPa:[0-9]+]], %hi(_gp_disp) +; CHECK-DAG: addiu $[[REG_GPb:[0-9]+]], $[[REG_GPa]], %lo(_gp_disp) +; CHECK-DAG: addu $[[REG_GP:[0-9]+]], $[[REG_GPb]], $25 +; CHECK-DAG: lw $[[S3_ADDR:[0-9]+]], %got(s3)($[[REG_GP]]) +; CHECK-DAG: lw $[[S2_ADDR:[0-9]+]], %got(s2)($[[REG_GP]]) +; CHECK-DAG: lw $[[S1_ADDR:[0-9]+]], %got(s1)($[[REG_GP]]) +; CHECK-DAG: lhu $[[S1:[0-9]+]], 0($[[S1_ADDR]]) +; CHECK-DAG: lhu $[[S2:[0-9]+]], 0($[[S2_ADDR]]) +; CHECK: srav $[[RES:[0-9]+]], $[[S1]], $[[S2]] +; CHECK: sh $[[RES]], 0($[[S3_ADDR]]) + ret void +} + +define void @srai() { +entry: + %0 = load i16, i16* @s1, align 2 + %shr = ashr i16 %0, 2 + store i16 %shr, i16* @s3, align 2 +; CHECK-LABEL: srai: +; CHECK: lui $[[REG_GPa:[0-9]+]], %hi(_gp_disp) +; CHECK-DAG: addiu $[[REG_GPb:[0-9]+]], $[[REG_GPa]], %lo(_gp_disp) +; CHECK-DAG: addu $[[REG_GP:[0-9]+]], $[[REG_GPb]], $25 +; CHECK-DAG: lw $[[S3_ADDR:[0-9]+]], %got(s3)($[[REG_GP]]) +; CHECK-DAG: lw $[[S1_ADDR:[0-9]+]], %got(s1)($[[REG_GP]]) +; CHECK-DAG: lhu $[[S1:[0-9]+]], 0($[[S1_ADDR]]) +; CHECK: sra $[[RES:[0-9]+]], $[[S1]], 2 +; CHECK: sh $[[RES]], 0($[[S3_ADDR]]) + ret void +}