Index: lib/Target/Mips/MipsFastISel.cpp =================================================================== --- lib/Target/Mips/MipsFastISel.cpp +++ lib/Target/Mips/MipsFastISel.cpp @@ -91,6 +91,7 @@ private: // Selection routines. + bool selectLogicalOp(const Instruction *I); bool selectLoad(const Instruction *I); bool selectStore(const Instruction *I); bool selectBranch(const Instruction *I); @@ -104,6 +105,7 @@ // Utility helper routines. bool isTypeLegal(Type *Ty, MVT &VT); + bool isTypeSupported(Type *Ty, MVT &VT, bool IsVectorAllowed = false); bool isLoadTypeLegal(Type *Ty, MVT &VT); bool computeAddress(const Value *Obj, Address &Addr, Type *Ty = nullptr); bool computeCallAddress(const Value *V, Address &Addr); @@ -130,6 +132,9 @@ unsigned getRegEnsuringSimpleIntegerWidening(const Value *, bool IsUnsigned); + unsigned emitLogicalOp(unsigned ISDOpc, MVT RetVT, const Value *LHS, + const Value *RHS); + unsigned materializeFP(const ConstantFP *CFP, MVT VT); unsigned materializeGV(const GlobalValue *GV, MVT VT); unsigned materializeInt(const Constant *C, MVT VT); @@ -218,6 +223,38 @@ return CC_MipsO32; } +unsigned MipsFastISel::emitLogicalOp(unsigned ISDOpc, MVT RetVT, + const Value *LHS, const Value *RHS) { + // Canonicalize immediates to the RHS first. + if (isa(LHS) && !isa(RHS)) + std::swap(LHS, RHS); + + unsigned Opc; + if (ISDOpc == ISD::AND) { + Opc = Mips::AND; + } else if (ISDOpc == ISD::OR) { + Opc = Mips::OR; + } else if (ISDOpc == ISD::XOR) { + Opc = Mips::XOR; + } else + llvm_unreachable("unexpected opcode"); + unsigned LHSReg = getRegForValue(LHS); + unsigned ResultReg = createResultReg(&Mips::GPR32RegClass); + if (!ResultReg) + return 0; + unsigned RHSReg; + if (!LHSReg) + return 0; + if (const auto *C = dyn_cast(RHS)) + RHSReg = materializeInt(C, MVT::i32); + else + RHSReg = getRegForValue(RHS); + if (!RHSReg) + return 0; + emitInst(Opc, ResultReg).addReg(LHSReg).addReg(RHSReg); + return ResultReg; +} + unsigned MipsFastISel::materializeInt(const Constant *C, MVT VT) { if (VT != MVT::i32 && VT != MVT::i16 && VT != MVT::i8 && VT != MVT::i1) return 0; @@ -432,6 +469,20 @@ return TLI.isTypeLegal(VT); } +bool MipsFastISel::isTypeSupported(Type *Ty, MVT &VT, bool IsVectorAllowed) { + if (Ty->isVectorTy() && !IsVectorAllowed) + return false; + + if (isTypeLegal(Ty, VT)) + return true; + + // If this is a type than can be sign or zero-extended to a basic operation + // go ahead and accept it now. + if (VT == MVT::i1 || VT == MVT::i8 || VT == MVT::i16) + return true; + + return false; +} bool MipsFastISel::isLoadTypeLegal(Type *Ty, MVT &VT) { if (isTypeLegal(Ty, VT)) return true; @@ -684,6 +735,30 @@ return false; } +bool MipsFastISel::selectLogicalOp(const Instruction *I) { + MVT VT; + if (!isTypeSupported(I->getType(), VT)) + return false; + unsigned ResultReg; + switch (I->getOpcode()) { + default: + llvm_unreachable("Unexpected instruction."); + case Instruction::And: + ResultReg = emitLogicalOp(ISD::AND, VT, I->getOperand(0), I->getOperand(1)); + break; + case Instruction::Or: + ResultReg = emitLogicalOp(ISD::OR, VT, I->getOperand(0), I->getOperand(1)); + break; + case Instruction::Xor: + ResultReg = emitLogicalOp(ISD::XOR, VT, I->getOperand(0), I->getOperand(1)); + break; + } + if (!ResultReg) + return false; + updateValueMap(I, ResultReg); + return true; +} + bool MipsFastISel::selectLoad(const Instruction *I) { // Atomic loads need special handling. if (cast(I)->isAtomic()) @@ -1329,6 +1404,10 @@ return selectLoad(I); case Instruction::Store: return selectStore(I); + case Instruction::And: + case Instruction::Or: + case Instruction::Xor: + return selectLogicalOp(I); case Instruction::Br: return selectBranch(I); case Instruction::Ret: Index: test/CodeGen/Mips/Fast-ISel/logopm.ll =================================================================== --- /dev/null +++ test/CodeGen/Mips/Fast-ISel/logopm.ll @@ -0,0 +1,210 @@ +; 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 + +; ModuleID = 'logop.c' +target datalayout = "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64" +target triple = "mipsel--linux-gnu" + +@i1_1 = global i8 1, align 1 +@i1_2 = global i8 0, align 1 +@i1_3 = global i8 1, align 1 +@i1_4 = global i8 1, align 1 +@i8_1 = global i8 5, align 1 +@i8_2 = global i8 -61, align 1 +@i16_1 = global i16 -7998, align 2 +@i16_2 = global i16 -3871, align 2 +@i32_1 = global i32 987717, align 4 +@i32_2 = global i32 15733009, align 4 +@j1_1 = common global i8 0, align 1 +@j1_2 = common global i8 0, align 1 +@j1_3 = common global i8 0, align 1 +@j1_4 = common global i8 0, align 1 +@j8_1 = common global i8 0, align 1 +@j8_2 = common global i8 0, align 1 +@j16_1 = common global i16 0, align 2 +@j16_2 = common global i16 0, align 2 +@j32_1 = common global i32 0, align 4 +@j32_2 = common global i32 0, align 4 + +; Function Attrs: nounwind +define void @i1_test() #0 { +entry: +; CHECK-LABEL: .ent i1_test + %0 = load i8* @i1_1, align 1 + %conv = trunc i8 %0 to i1 + %and = and i1 1, %conv +; CHECK: and ${{[0-9]+}}, ${{[0-9]+}}, ${{[0-9]+}} + %conv1 = zext i1 %and to i8 + store i8 %conv1, i8* @j1_1, align 1 + %1 = load i8* @i1_1, align 1 + %conv2 = trunc i8 %1 to i1 + %2 = load i8* @i1_2, align 1 + %conv3 = trunc i8 %2 to i1 + %and4 = and i1 %conv2, %conv3 +; CHECK: and ${{[0-9]+}}, ${{[0-9]+}}, ${{[0-9]+}} + %conv5 = zext i1 %and4 to i8 + store i8 %conv5, i8* @j1_2, align 1 + %3 = load i8* @i1_2, align 1 + %conv6 = trunc i8 %3 to i1 + %4 = load i8* @i1_3, align 1 + %conv7 = trunc i8 %4 to i1 + %and8 = and i1 %conv6, %conv7 +; CHECK: and ${{[0-9]+}}, ${{[0-9]+}}, ${{[0-9]+}} + %conv9 = zext i1 %and8 to i8 + store i8 %conv9, i8* @j1_3, align 1 + %5 = load i8* @i1_3, align 1 + %conv10 = trunc i8 %5 to i1 + %6 = load i8* @i1_4, align 1 + %conv11 = trunc i8 %6 to i1 + %and12 = and i1 %conv10, %conv11 +; CHECK: and ${{[0-9]+}}, ${{[0-9]+}}, ${{[0-9]+}} + %conv13 = zext i1 %and12 to i8 + store i8 %conv13, i8* @j1_4, align 1 + ret void +} + +; Function Attrs: nounwind +define void @i8_test() #0 { +entry: +; CHECK-LABEL: .ent i8_test + %0 = load i8* @i8_1, align 1 + %or = or i8 %0, 225 + store i8 %or, i8* @j8_1, align 1 +; CHECK: or ${{[0-9]+}}, ${{[0-9]+}}, ${{[0-9]+}} + %1 = load i8* @i8_1, align 1 + %2 = load i8* @i8_2, align 1 + %or4 = or i8 %1, %2 +; CHECK: or ${{[0-9]+}}, ${{[0-9]+}}, ${{[0-9]+}} + store i8 %or4, i8* @j8_2, align 1 + ret void +} + +; Function Attrs: nounwind +define void @i16_test() #0 { +entry: +; CHECK-LABEL: .ent i16_test + %0 = load i16* @i16_1, align 2 + %xor = xor i16 241, %0 + store i16 %xor, i16* @j16_1, align 2 +; CHECK: xor ${{[0-9]+}}, ${{[0-9]+}}, ${{[0-9]+}} + %1 = load i16* @i16_1, align 2 + %2 = load i16* @i16_2, align 2 + %xor4 = xor i16 %1, %2 +; CHECK: xor ${{[0-9]+}}, ${{[0-9]+}}, ${{[0-9]+}} + store i16 %xor4, i16* @j16_2, align 2 + ret void +} + +; Function Attrs: nounwind +define void @i32_test() #0 { +entry: + %0 = load i32* @i32_1, align 4 + %xor = xor i32 %0, -16908096 + store i32 %xor, i32* @j32_1, align 4 + %1 = load i32* @i32_1, align 4 + %2 = load i32* @i32_2, align 4 + %xor1 = xor i32 %1, %2 + store i32 %xor1, i32* @j32_2, align 4 + ret void +} + +; Function Attrs: nounwind +define i32 @main() #0 { +entry: + %retval = alloca i32, align 4 + store i32 0, i32* %retval + call void @i1_test() + %0 = load i8* @j1_1, align 1 + %conv = sext i8 %0 to i32 + %cmp = icmp ne i32 %conv, 1 + br i1 %cmp, label %if.then, label %lor.lhs.false + +lor.lhs.false: ; preds = %entry + %1 = load i8* @j1_2, align 1 + %conv2 = sext i8 %1 to i32 + %cmp3 = icmp ne i32 %conv2, 0 + br i1 %cmp3, label %if.then, label %lor.lhs.false5 + +lor.lhs.false5: ; preds = %lor.lhs.false + %2 = load i8* @j1_3, align 1 + %conv6 = sext i8 %2 to i32 + %cmp7 = icmp ne i32 %conv6, 0 + br i1 %cmp7, label %if.then, label %lor.lhs.false9 + +lor.lhs.false9: ; preds = %lor.lhs.false5 + %3 = load i8* @j1_4, align 1 + %conv10 = sext i8 %3 to i32 + %cmp11 = icmp ne i32 %conv10, 1 + br i1 %cmp11, label %if.then, label %if.end + +if.then: ; preds = %lor.lhs.false9, %lor.lhs.false5, %lor.lhs.false, %entry + call void @abort() #2 + unreachable + +if.end: ; preds = %lor.lhs.false9 + call void @i8_test() + %4 = load i8* @j8_1, align 1 + %conv13 = zext i8 %4 to i32 + %cmp14 = icmp ne i32 %conv13, 229 + br i1 %cmp14, label %if.then20, label %lor.lhs.false16 + +lor.lhs.false16: ; preds = %if.end + %5 = load i8* @j8_2, align 1 + %conv17 = zext i8 %5 to i32 + %cmp18 = icmp ne i32 %conv17, 199 + br i1 %cmp18, label %if.then20, label %if.end21 + +if.then20: ; preds = %lor.lhs.false16, %if.end + call void @abort() #2 + unreachable + +if.end21: ; preds = %lor.lhs.false16 + call void @i16_test() + %6 = load i16* @j16_1, align 2 + %conv22 = zext i16 %6 to i32 + %cmp23 = icmp ne i32 %conv22, 57395 + br i1 %cmp23, label %if.then29, label %lor.lhs.false25 + +lor.lhs.false25: ; preds = %if.end21 + %7 = load i16* @j16_2, align 2 + %conv26 = zext i16 %7 to i32 + %cmp27 = icmp ne i32 %conv26, 4131 + br i1 %cmp27, label %if.then29, label %if.end30 + +if.then29: ; preds = %lor.lhs.false25, %if.end21 + call void @abort() #2 + unreachable + +if.end30: ; preds = %lor.lhs.false25 + call void @i32_test() + %8 = load i32* @j32_1, align 4 + %cmp31 = icmp ne i32 %8, -17755515 + br i1 %cmp31, label %if.then36, label %lor.lhs.false33 + +lor.lhs.false33: ; preds = %if.end30 + %9 = load i32* @j32_2, align 4 + %cmp34 = icmp ne i32 %9, 16712532 + br i1 %cmp34, label %if.then36, label %if.end37 + +if.then36: ; preds = %lor.lhs.false33, %if.end30 + call void @abort() #2 + unreachable + +if.end37: ; preds = %lor.lhs.false33 + ret i32 0 +} + +; Function Attrs: noreturn +declare void @abort() #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 = { noreturn "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 #2 = { noreturn } + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = metadata !{i32 1, metadata !"PIC Level", i32 2} +!1 = metadata !{metadata !"clang version 3.6.0 (gitosis@dmz-portal.mips.com:clang.git 59d05423ef08bc76eeedb88bb7bfa0b0e0415711) (gitosis@dmz-portal.mips.com:llvm.git 431113b8f2ea22b437e86d06a0ce5fbe78e2d4cb)"}