From 8a6f79e58de6da1a08d5f4d40cb468bb3cfdc333 Mon Sep 17 00:00:00 2001 From: Reed Kotler Date: Tue, 30 Sep 2014 16:30:13 +0000 Subject: [PATCH] Add numeric extend, trunctate to mips fast-isel Summary: Add numeric extend, trunctate to mips fast-isel Reactivates D4827 Test Plan: fpext.ll loadstoreconv.ll Reviewers: dsanders Subscribers: mcrosier Differential Revision: http://reviews.llvm.org/D5251 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@218681 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/Mips/MipsFastISel.cpp | 173 +++++++++++++++++- test/CodeGen/Mips/Fast-ISel/fpext.ll | 21 +++ test/CodeGen/Mips/Fast-ISel/loadstoreconv.ll | 179 +++++++++++++++++++ 3 files changed, 368 insertions(+), 5 deletions(-) create mode 100644 test/CodeGen/Mips/Fast-ISel/fpext.ll create mode 100644 test/CodeGen/Mips/Fast-ISel/loadstoreconv.ll diff --git a/lib/Target/Mips/MipsFastISel.cpp b/lib/Target/Mips/MipsFastISel.cpp index e5857a0100e..bd3d08527b7 100644 --- a/lib/Target/Mips/MipsFastISel.cpp +++ b/lib/Target/Mips/MipsFastISel.cpp @@ -78,6 +78,9 @@ private: bool SelectLoad(const Instruction *I); bool SelectRet(const Instruction *I); bool SelectStore(const Instruction *I); + bool SelectIntExt(const Instruction *I); + bool SelectTrunc(const Instruction *I); + bool SelectFPExt(const Instruction *I); bool isTypeLegal(Type *Ty, MVT &VT); bool isLoadTypeLegal(Type *Ty, MVT &VT); @@ -87,6 +90,16 @@ private: unsigned MaterializeInt(const Constant *C, MVT VT); unsigned Materialize32BitInt(int64_t Imm, const TargetRegisterClass *RC); + bool EmitIntExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, unsigned DestReg, + bool IsZExt); + + bool EmitIntZExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, unsigned DestReg); + + bool EmitIntSExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, unsigned DestReg); + bool EmitIntSExt32r1(MVT SrcVT, unsigned SrcReg, MVT DestVT, + unsigned DestReg); + bool EmitIntSExt32r2(MVT SrcVT, unsigned SrcReg, MVT DestVT, + unsigned DestReg); // for some reason, this default is not generated by tablegen // so we explicitly generate it here. // @@ -242,6 +255,74 @@ bool MipsFastISel::EmitStore(MVT VT, unsigned SrcReg, Address &Addr, return true; } +bool MipsFastISel::EmitIntSExt32r1(MVT SrcVT, unsigned SrcReg, MVT DestVT, + unsigned DestReg) { + unsigned ShiftAmt; + switch (SrcVT.SimpleTy) { + default: + return false; + case MVT::i8: + ShiftAmt = 24; + break; + case MVT::i16: + ShiftAmt = 16; + break; + } + unsigned TempReg = createResultReg(&Mips::GPR32RegClass); + EmitInst(Mips::SLL, TempReg).addReg(SrcReg).addImm(ShiftAmt); + EmitInst(Mips::SRA, DestReg).addReg(TempReg).addImm(ShiftAmt); + return true; +} + +bool MipsFastISel::EmitIntSExt32r2(MVT SrcVT, unsigned SrcReg, MVT DestVT, + unsigned DestReg) { + switch (SrcVT.SimpleTy) { + default: + return false; + case MVT::i8: + EmitInst(Mips::SEB, DestReg).addReg(SrcReg); + break; + case MVT::i16: + EmitInst(Mips::SEH, DestReg).addReg(SrcReg); + break; + } + return true; +} + +bool MipsFastISel::EmitIntExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, + unsigned DestReg, bool IsZExt) { + if (IsZExt) + return EmitIntZExt(SrcVT, SrcReg, DestVT, DestReg); + return EmitIntSExt(SrcVT, SrcReg, DestVT, DestReg); +} + +bool MipsFastISel::EmitIntSExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, + unsigned DestReg) { + if ((DestVT != MVT::i32) && (DestVT != MVT::i16)) + return false; + if (Subtarget->hasMips32r2()) + return EmitIntSExt32r2(SrcVT, SrcReg, DestVT, DestReg); + return EmitIntSExt32r1(SrcVT, SrcReg, DestVT, DestReg); +} + +bool MipsFastISel::EmitIntZExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, + unsigned DestReg) { + switch (SrcVT.SimpleTy) { + default: + return false; + case MVT::i1: + EmitInst(Mips::ANDi, DestReg).addReg(SrcReg).addImm(1); + break; + case MVT::i8: + EmitInst(Mips::ANDi, DestReg).addReg(SrcReg).addImm(0xff); + break; + case MVT::i16: + EmitInst(Mips::ANDi, DestReg).addReg(SrcReg).addImm(0xffff); + break; + } + return true; +} + bool MipsFastISel::SelectLoad(const Instruction *I) { // Atomic loads need special handling. if (cast(I)->isAtomic()) @@ -304,6 +385,79 @@ bool MipsFastISel::SelectRet(const Instruction *I) { return true; } +// Attempt to fast-select a floating-point extend instruction. +bool MipsFastISel::SelectFPExt(const Instruction *I) { + Value *Src = I->getOperand(0); + EVT SrcVT = TLI.getValueType(Src->getType(), true); + EVT DestVT = TLI.getValueType(I->getType(), true); + + if (SrcVT != MVT::f32 || DestVT != MVT::f64) + return false; + + unsigned SrcReg = + getRegForValue(Src); // his must be a 32 bit floating point register class + // maybe we should handle this differently + if (!SrcReg) + return false; + + unsigned DestReg = createResultReg(&Mips::AFGR64RegClass); + EmitInst(Mips::CVT_D32_S, DestReg).addReg(SrcReg); + updateValueMap(I, DestReg); + return true; +} + +bool MipsFastISel::SelectIntExt(const Instruction *I) { + Type *DestTy = I->getType(); + Value *Src = I->getOperand(0); + Type *SrcTy = Src->getType(); + + bool isZExt = isa(I); + unsigned SrcReg = getRegForValue(Src); + if (!SrcReg) + return false; + + EVT SrcEVT, DestEVT; + SrcEVT = TLI.getValueType(SrcTy, true); + DestEVT = TLI.getValueType(DestTy, true); + if (!SrcEVT.isSimple()) + return false; + if (!DestEVT.isSimple()) + return false; + + MVT SrcVT = SrcEVT.getSimpleVT(); + MVT DestVT = DestEVT.getSimpleVT(); + unsigned ResultReg = createResultReg(&Mips::GPR32RegClass); + + if (!EmitIntExt(SrcVT, SrcReg, DestVT, ResultReg, isZExt)) + return false; + updateValueMap(I, ResultReg); + return true; +} + +bool MipsFastISel::SelectTrunc(const Instruction *I) { + // The high bits for a type smaller than the register size are assumed to be + // undefined. + Value *Op = I->getOperand(0); + + EVT SrcVT, DestVT; + SrcVT = TLI.getValueType(Op->getType(), true); + DestVT = TLI.getValueType(I->getType(), true); + + if (SrcVT != MVT::i32 && SrcVT != MVT::i16 && SrcVT != MVT::i8) + return false; + if (DestVT != MVT::i16 && DestVT != MVT::i8 && DestVT != MVT::i1) + return false; + + unsigned SrcReg = getRegForValue(Op); + if (!SrcReg) + return false; + + // Because the high bits are undefined, a truncate doesn't generate + // any code. + updateValueMap(I, SrcReg); + return true; +} + bool MipsFastISel::fastSelectInstruction(const Instruction *I) { if (!TargetSupported) return false; @@ -316,10 +470,16 @@ bool MipsFastISel::fastSelectInstruction(const Instruction *I) { return SelectStore(I); case Instruction::Ret: return SelectRet(I); + case Instruction::Trunc: + return SelectTrunc(I); + case Instruction::ZExt: + case Instruction::SExt: + return SelectIntExt(I); + case Instruction::FPExt: + return SelectFPExt(I); } return false; } -} unsigned MipsFastISel::MaterializeFP(const ConstantFP *CFP, MVT VT) { int64_t Imm = CFP->getValueAPF().bitcastToAPInt().getZExtValue(); @@ -352,13 +512,15 @@ unsigned MipsFastISel::MaterializeGV(const GlobalValue *GV, MVT VT) { // TLS not supported at this time. if (IsThreadLocal) return 0; - EmitInst(Mips::LW, DestReg).addReg(MFI->getGlobalBaseReg()).addGlobalAddress( - GV, 0, MipsII::MO_GOT); + EmitInst(Mips::LW, DestReg) + .addReg(MFI->getGlobalBaseReg()) + .addGlobalAddress(GV, 0, MipsII::MO_GOT); if ((GV->hasInternalLinkage() || (GV->hasLocalLinkage() && !isa(GV)))) { unsigned TempReg = createResultReg(RC); - EmitInst(Mips::ADDiu, TempReg).addReg(DestReg).addGlobalAddress( - GV, 0, MipsII::MO_ABS_LO); + EmitInst(Mips::ADDiu, TempReg) + .addReg(DestReg) + .addGlobalAddress(GV, 0, MipsII::MO_ABS_LO); DestReg = TempReg; } return DestReg; @@ -401,6 +563,7 @@ unsigned MipsFastISel::Materialize32BitInt(int64_t Imm, } return ResultReg; } +} namespace llvm { FastISel *Mips::createFastISel(FunctionLoweringInfo &funcInfo, diff --git a/test/CodeGen/Mips/Fast-ISel/fpext.ll b/test/CodeGen/Mips/Fast-ISel/fpext.ll new file mode 100644 index 00000000000..98aca756c58 --- /dev/null +++ b/test/CodeGen/Mips/Fast-ISel/fpext.ll @@ -0,0 +1,21 @@ +; RUN: llc -march=mipsel -relocation-model=pic -O0 -mips-fast-isel -fast-isel-abort -mcpu=mips32r2 \ +; RUN: < %s | FileCheck %s +; RUN: llc -march=mipsel -relocation-model=pic -O0 -mips-fast-isel -fast-isel-abort -mcpu=mips32 \ +; RUN: < %s | FileCheck %s + +@f = global float 0x40147E6B80000000, align 4 +@d_f = common global double 0.000000e+00, align 8 +@.str = private unnamed_addr constant [6 x i8] c"%f \0A\00", align 1 + +; Function Attrs: nounwind +define void @dv() #0 { +entry: + %0 = load float* @f, align 4 + %conv = fpext float %0 to double +; CHECK: cvt.d.s $f{{[0-9]+}}, $f{{[0-9]+}} + store double %conv, double* @d_f, align 8 + ret void +} + + +attributes #1 = { nounwind } diff --git a/test/CodeGen/Mips/Fast-ISel/loadstoreconv.ll b/test/CodeGen/Mips/Fast-ISel/loadstoreconv.ll new file mode 100644 index 00000000000..f7f2c6481b3 --- /dev/null +++ b/test/CodeGen/Mips/Fast-ISel/loadstoreconv.ll @@ -0,0 +1,179 @@ +; RUN: llc -march=mipsel -relocation-model=pic -O0 -mips-fast-isel -fast-isel-abort -mcpu=mips32r2 \ +; RUN: < %s | FileCheck %s +; RUN: llc -march=mipsel -relocation-model=pic -O0 -mips-fast-isel -fast-isel-abort -mcpu=mips32 \ +; RUN: < %s | FileCheck %s +; RUN: llc -march=mipsel -relocation-model=pic -O0 -mips-fast-isel -fast-isel-abort -mcpu=mips32r2 \ +; RUN: < %s | FileCheck %s -check-prefix=mips32r2 +; RUN: llc -march=mipsel -relocation-model=pic -O0 -mips-fast-isel -fast-isel-abort -mcpu=mips32 \ +; RUN: < %s | FileCheck %s -check-prefix=mips32 + +@b2 = global i8 0, align 1 +@b1 = global i8 1, align 1 +@uc1 = global i8 0, align 1 +@uc2 = global i8 -1, align 1 +@sc1 = global i8 -128, align 1 +@sc2 = global i8 127, align 1 +@ss1 = global i16 -32768, align 2 +@ss2 = global i16 32767, align 2 +@us1 = global i16 0, align 2 +@us2 = global i16 -1, align 2 +@ssi = global i16 0, align 2 +@ssj = global i16 0, align 2 +@i = global i32 0, align 4 +@j = global i32 0, align 4 +@.str = private unnamed_addr constant [4 x i8] c"%i\0A\00", align 1 +@.str1 = private unnamed_addr constant [7 x i8] c"%i %i\0A\00", align 1 + +; Function Attrs: nounwind +define void @_Z3b_iv() { +entry: +; CHECK-LABEL: .ent _Z3b_iv + %0 = load i8* @b1, align 1 + %tobool = trunc i8 %0 to i1 + %frombool = zext i1 %tobool to i8 + store i8 %frombool, i8* @b2, align 1 + %1 = load i8* @b2, align 1 + %tobool1 = trunc i8 %1 to i1 + %conv = zext i1 %tobool1 to i32 + store i32 %conv, i32* @i, align 4 +; CHECK: lbu $[[REG1:[0-9]+]], 0(${{[0-9]+}}) +; CHECK: andi $[[REG2:[0-9]+]], $[[REG1]], 1 +; CHECK: sb $[[REG2]], 0(${{[0-9]+}}) + + + + ret void +; CHECK: .end _Z3b_iv +} + +; Function Attrs: nounwind +define void @_Z4uc_iv() { +entry: +; CHECK-LABEL: .ent _Z4uc_iv + + %0 = load i8* @uc1, align 1 + %conv = zext i8 %0 to i32 + store i32 %conv, i32* @i, align 4 + %1 = load i8* @uc2, align 1 + %conv1 = zext i8 %1 to i32 +; CHECK: lbu $[[REG1:[0-9]+]], 0(${{[0-9]+}}) +; CHECK: andi ${{[0-9]+}}, $[[REG1]], 255 + + store i32 %conv1, i32* @j, align 4 + ret void +; CHECK: .end _Z4uc_iv + +} + +; Function Attrs: nounwind +define void @_Z4sc_iv() { +entry: +; mips32r2-LABEL: .ent _Z4sc_iv +; mips32-LABEL: .ent _Z4sc_iv + + %0 = load i8* @sc1, align 1 + %conv = sext i8 %0 to i32 + store i32 %conv, i32* @i, align 4 + %1 = load i8* @sc2, align 1 + %conv1 = sext i8 %1 to i32 + store i32 %conv1, i32* @j, align 4 +; mips32r2: lbu $[[REG1:[0-9]+]], 0(${{[0-9]+}}) +; mips32r2: seb ${{[0-9]+}}, $[[REG1]] +; mips32: lbu $[[REG1:[0-9]+]], 0(${{[0-9]+}}) +; mips32: sll $[[REG2:[0-9]+]], $[[REG1]], 24 +; mips32: sra ${{[0-9]+}}, $[[REG2]], 24 + + ret void +; CHECK: .end _Z4sc_iv +} + +; Function Attrs: nounwind +define void @_Z4us_iv() { +entry: +; CHECK-LABEL: .ent _Z4us_iv + %0 = load i16* @us1, align 2 + %conv = zext i16 %0 to i32 + store i32 %conv, i32* @i, align 4 + %1 = load i16* @us2, align 2 + %conv1 = zext i16 %1 to i32 + store i32 %conv1, i32* @j, align 4 + ret void +; CHECK: lhu $[[REG1:[0-9]+]], 0(${{[0-9]+}}) +; CHECK: andi ${{[0-9]+}}, $[[REG1]], 65535 +; CHECK: .end _Z4us_iv +} + +; Function Attrs: nounwind +define void @_Z4ss_iv() { +entry: +; mips32r2-LABEL: .ent _Z4ss_iv +; mips32=LABEL: .ent _Z4ss_iv + + %0 = load i16* @ss1, align 2 + %conv = sext i16 %0 to i32 + store i32 %conv, i32* @i, align 4 + %1 = load i16* @ss2, align 2 + %conv1 = sext i16 %1 to i32 + store i32 %conv1, i32* @j, align 4 +; mips32r2: lhu $[[REG1:[0-9]+]], 0(${{[0-9]+}}) +; mips32r2: seh ${{[0-9]+}}, $[[REG1]] +; mips32: lhu $[[REG1:[0-9]+]], 0(${{[0-9]+}}) +; mips32: sll $[[REG2:[0-9]+]], $[[REG1]], 16 +; mips32: sra ${{[0-9]+}}, $[[REG2]], 16 + + ret void +; CHECK: .end _Z4ss_iv +} + +; Function Attrs: nounwind +define void @_Z4b_ssv() { +entry: +; CHECK-LABEL: .ent _Z4b_ssv + %0 = load i8* @b2, align 1 + %tobool = trunc i8 %0 to i1 + %conv = zext i1 %tobool to i16 + store i16 %conv, i16* @ssi, align 2 + ret void +; CHECK: lbu $[[REG1:[0-9]+]], 0(${{[0-9]+}}) +; CHECK: andi ${{[0-9]+}}, $[[REG1]], 1 +; CHECK: .end _Z4b_ssv +} + +; Function Attrs: nounwind +define void @_Z5uc_ssv() { +entry: +; CHECK-LABEL: .ent _Z5uc_ssv + %0 = load i8* @uc1, align 1 + %conv = zext i8 %0 to i16 + store i16 %conv, i16* @ssi, align 2 + %1 = load i8* @uc2, align 1 + %conv1 = zext i8 %1 to i16 +; CHECK: lbu $[[REG1:[0-9]+]], 0(${{[0-9]+}}) +; CHECK: andi ${{[0-9]+}}, $[[REG1]], 255 + + store i16 %conv1, i16* @ssj, align 2 + ret void +; CHECK: .end _Z5uc_ssv +} + +; Function Attrs: nounwind +define void @_Z5sc_ssv() { +entry: +; mips32r2-LABEL: .ent _Z5sc_ssv +; mips32-LABEL: .ent _Z5sc_ssv + %0 = load i8* @sc1, align 1 + %conv = sext i8 %0 to i16 + store i16 %conv, i16* @ssi, align 2 + %1 = load i8* @sc2, align 1 + %conv1 = sext i8 %1 to i16 + store i16 %conv1, i16* @ssj, align 2 +; mips32r2: lbu $[[REG1:[0-9]+]], 0(${{[0-9]+}}) +; mips32r2: seb ${{[0-9]+}}, $[[REG1]] +; mips32: lbu $[[REG1:[0-9]+]], 0(${{[0-9]+}}) +; mips32: sll $[[REG2:[0-9]+]], $[[REG1]], 24 +; mips32: sra ${{[0-9]+}}, $[[REG2]], 24 + + ret void +; CHECK: .end _Z5sc_ssv +} +