Index: lib/Target/Mips/MipsFastISel.cpp =================================================================== --- lib/Target/Mips/MipsFastISel.cpp +++ lib/Target/Mips/MipsFastISel.cpp @@ -79,6 +79,7 @@ LLVMContext *Context; bool fastLowerCall(CallLoweringInfo &CLI) override; + bool fastLowerIntrinsicCall(const IntrinsicInst *II) override; bool TargetSupported; bool UnsupportedFPMode; // To allow fast-isel to proceed and just not handle @@ -140,6 +141,7 @@ unsigned materializeGV(const GlobalValue *GV, MVT VT); unsigned materializeInt(const Constant *C, MVT VT); unsigned materialize32BitInt(int64_t Imm, const TargetRegisterClass *RC); + unsigned materializeExternalCallSym(const char *SynName); MachineInstrBuilder emitInst(unsigned Opc) { return BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)); @@ -366,6 +368,15 @@ return DestReg; } +unsigned MipsFastISel::materializeExternalCallSym(const char *SymName) { + const TargetRegisterClass *RC = &Mips::GPR32RegClass; + unsigned DestReg = createResultReg(RC); + emitInst(Mips::LW, DestReg) + .addReg(MFI->getGlobalBaseReg()) + .addExternalSymbol(SymName, MipsII::MO_GOT); + return DestReg; +} + // Materialize a constant into a register, and return the register // number (or zero if we failed to handle it). unsigned MipsFastISel::fastMaterializeConstant(const Constant *C) { @@ -473,15 +484,51 @@ } bool MipsFastISel::computeCallAddress(const Value *V, Address &Addr) { - const GlobalValue *GV = dyn_cast(V); - if (GV && isa(GV) && dyn_cast(GV)->isIntrinsic()) - return false; - if (!GV) - return false; + const User *U = nullptr; + unsigned Opcode = Instruction::UserOp1; + bool InMBB = true; + + if (const auto *I = dyn_cast(V)) { + Opcode = I->getOpcode(); + U = I; + InMBB = I->getParent() == FuncInfo.MBB->getBasicBlock(); + } else if (const auto *C = dyn_cast(V)) { + Opcode = C->getOpcode(); + U = C; + } + + switch (Opcode) { + default: + break; + case Instruction::BitCast: + // Look past bitcasts if its operand is in the same BB. + if (InMBB) + return computeCallAddress(U->getOperand(0), Addr); + break; + case Instruction::IntToPtr: + // Look past no-op inttoptrs if its operand is in the same BB. + if (InMBB && + TLI.getValueType(U->getOperand(0)->getType()) == TLI.getPointerTy()) + return computeCallAddress(U->getOperand(0), Addr); + break; + case Instruction::PtrToInt: + // Look past no-op ptrtoints if its operand is in the same BB. + if (InMBB && TLI.getValueType(U->getType()) == TLI.getPointerTy()) + return computeCallAddress(U->getOperand(0), Addr); + break; + } + if (const GlobalValue *GV = dyn_cast(V)) { Addr.setGlobalValue(GV); return true; } + + // If all else fails, try to materialize the value in a register. + if (!Addr.getGlobalValue()) { + Addr.setReg(getRegForValue(V)); + return Addr.getReg() != 0; + } + return false; } @@ -1211,7 +1258,7 @@ bool IsTailCall = CLI.IsTailCall; bool IsVarArg = CLI.IsVarArg; const Value *Callee = CLI.Callee; - // const char *SymName = CLI.SymName; + const char *SymName = CLI.SymName; // Allow SelectionDAG isel to handle tail calls. if (IsTailCall) @@ -1258,8 +1305,15 @@ if (!processCallArgs(CLI, OutVTs, NumBytes)) return false; + if (!Addr.getGlobalValue()) + return false; + // Issue the call. - unsigned DestAddress = materializeGV(Addr.getGlobalValue(), MVT::i32); + unsigned DestAddress; + if (SymName) + DestAddress = materializeExternalCallSym(SymName); + else + DestAddress = materializeGV(Addr.getGlobalValue(), MVT::i32); emitInst(TargetOpcode::COPY, Mips::T9).addReg(DestAddress); MachineInstrBuilder MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Mips::JALR), @@ -1279,6 +1333,34 @@ return finishCall(CLI, RetVT, NumBytes); } +bool MipsFastISel::fastLowerIntrinsicCall(const IntrinsicInst *II) { + switch (II->getIntrinsicID()) { + default: + return false; + case Intrinsic::memcpy: + case Intrinsic::memmove: { + const auto *MTI = cast(II); + // Don't handle volatile. + if (MTI->isVolatile()) + return false; + if (!MTI->getLength()->getType()->isIntegerTy(32)) + return false; + const char *IntrMemName = isa(II) ? "memcpy" : "memmove"; + return lowerCallTo(II, IntrMemName, II->getNumArgOperands() - 2); + } + case Intrinsic::memset: { + const MemSetInst *MSI = cast(II); + // Don't handle volatile. + if (MSI->isVolatile()) + return false; + if (!MSI->getLength()->getType()->isIntegerTy(32)) + return false; + return lowerCallTo(II, "memset", II->getNumArgOperands() - 2); + } + } + return false; +} + bool MipsFastISel::selectRet(const Instruction *I) { const Function &F = *I->getParent()->getParent(); const ReturnInst *Ret = cast(I); Index: test/CodeGen/Mips/Fast-ISel/memtest1.ll =================================================================== --- /dev/null +++ test/CodeGen/Mips/Fast-ISel/memtest1.ll @@ -0,0 +1,60 @@ +; RUN: llc -march=mipsel -relocation-model=pic -O0 -mips-fast-isel -fast-isel-abort -mcpu=mips32r2 \ +; RUN: < %s | FileCheck %s + +@.str = private unnamed_addr constant [12 x i8] c"hello there\00", align 1 +@src = global i8* getelementptr inbounds ([12 x i8]* @.str, i32 0, i32 0), align 4 +@i = global i32 12, align 4 +@j = global i32 50, align 4 +@dest = common global [50 x i8] zeroinitializer, align 1 + +; Function Attrs: nounwind +define void @cpy() #0 { +entry: +; CHECK-LABEL: .ent cpy + %0 = load i8** @src, align 4 + %1 = load i32* @i, align 4 + call void @llvm.memcpy.p0i8.p0i8.i32(i8* getelementptr inbounds ([50 x i8]* @dest, i32 0, i32 0), i8* %0, i32 %1, i32 1, i1 false) +; CHECK: lw ${{[0-9]+}}, %got(memcpy)(${{[0-9]+}}) + ret void +} + +; Function Attrs: nounwind +declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture, i8* nocapture readonly, i32, i32, i1) #1 + +; Function Attrs: nounwind +define void @mov() #0 { +entry: +; CHECK-LABEL: .ent mov + + %0 = load i8** @src, align 4 + %1 = load i32* @i, align 4 + call void @llvm.memmove.p0i8.p0i8.i32(i8* getelementptr inbounds ([50 x i8]* @dest, i32 0, i32 0), i8* %0, i32 %1, i32 1, i1 false) +; CHECK: lw ${{[0-9]+}}, %got(memmove)(${{[0-9]+}}) + ret void +} + +; Function Attrs: nounwind +declare void @llvm.memmove.p0i8.p0i8.i32(i8* nocapture, i8* nocapture readonly, i32, i32, i1) #1 + +; Function Attrs: nounwind +define void @clear() #0 { +entry: +; CHECK-LABEL: .ent clear + %0 = load i32* @i, align 4 + call void @llvm.memset.p0i8.i32(i8* getelementptr inbounds ([50 x i8]* @dest, i32 0, i32 0), i8 42, i32 %0, i32 1, i1 false) +; CHECK: lw ${{[0-9]+}}, %got(memset)(${{[0-9]+}}) + store i8 0, i8* getelementptr inbounds ([50 x i8]* @dest, i32 0, i32 12), align 1 + ret void +} + +; Function Attrs: nounwind +declare void @llvm.memset.p0i8.i32(i8* nocapture, i8, i32, i32, i1) #1 + +attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind } + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"PIC Level", i32 2} +!1 = !{!"clang version 3.7.0 (gitosis@dmz-portal.mips.com:clang.git 7646e9bd27a2569f650fb7f9ff81e03e5d8d4112) (gitosis@dmz-portal.mips.com:llvm.git 2f0ec9b0177e6d3922bf3cf9002fc92a09ef613f)"}