Index: lib/Target/ARM/ARMTargetTransformInfo.cpp =================================================================== --- lib/Target/ARM/ARMTargetTransformInfo.cpp +++ lib/Target/ARM/ARMTargetTransformInfo.cpp @@ -126,6 +126,13 @@ return 0; } + // xor a, -1 can always be folded to MVN + if (Opcode == Instruction::Xor) { + int64_t NegImm = Imm.getSExtValue(); + if (NegImm == -1) + return 0; + } + return getIntImmCost(Imm, Ty); } Index: test/CodeGen/Thumb/mvn.ll =================================================================== --- /dev/null +++ test/CodeGen/Thumb/mvn.ll @@ -0,0 +1,136 @@ +; RUN: llc -mtriple=thumbv6m-eabi %s -o - | FileCheck %s + +; CHECK-LABEL: test8 +; CHECK: mvn +define void @test8(i8* %a) { + %x = load i8, i8* %a + %xn = xor i8 %x, -1 + store i8 %xn, i8* %a + ret void +} + +; CHECK-LABEL: test8_2 +; CHECK: mvn +; CHECK: mvn +define void @test8_2(i8* %a, i8* %b) { + %x = load i8, i8* %a + %y = load i8, i8* %b + %xn = xor i8 %x, -1 + %yn = xor i8 %y, -1 + store i8 %xn, i8* %a + store i8 %yn, i8* %b + ret void +} + +; CHECK-LABEL: loop8 +; CHECK: mvn +define void @loop8(i8* %a) { +entry: + br label %for.body + +for.body: + %i = phi i32 [ 0, %entry ], [ %inc, %for.body ] + %arrayidx = getelementptr inbounds i8, i8* %a, i32 %i + %x = load i8, i8* %arrayidx + %xn = xor i8 %x, -1 + store i8 %xn, i8* %arrayidx + %inc = add nuw nsw i32 %i, 1 + %exitcond = icmp eq i32 %inc, 10 + br i1 %exitcond, label %for.cond.cleanup, label %for.body + +for.cond.cleanup: + ret void +} + +; CHECK-LABEL: loop8_2 +; CHECK: mvn +; CHECK: mvn +define void @loop8_2(i8* %a, i8* %b) { +entry: + br label %for.body + +for.body: + %i = phi i32 [ 0, %entry ], [ %inc, %for.body ] + %arrayidx = getelementptr inbounds i8, i8* %a, i32 %i + %arrayidx2 = getelementptr inbounds i8, i8* %b, i32 %i + %x = load i8, i8* %arrayidx + %y = load i8, i8* %arrayidx2 + %xn = xor i8 %x, -1 + %yn = xor i8 %y, -1 + store i8 %xn, i8* %arrayidx + store i8 %yn, i8* %arrayidx2 + %inc = add nuw nsw i32 %i, 1 + %exitcond = icmp eq i32 %inc, 10 + br i1 %exitcond, label %for.cond.cleanup, label %for.body + +for.cond.cleanup: + ret void +} + +; CHECK-LABEL: test32 +; CHECK: mvn +define void @test32(i32* %a) { + %x = load i32, i32* %a + %xn = xor i32 %x, -1 + store i32 %xn, i32* %a + ret void +} + +; CHECK-LABEL: test32_2 +; CHECK: mvn +; CHECK: mvn +define void @test32_2(i32* %a, i32* %b) { + %x = load i32, i32* %a + %y = load i32, i32* %b + %xn = xor i32 %x, -1 + %yn = xor i32 %y, -1 + store i32 %xn, i32* %a + store i32 %yn, i32* %b + ret void +} + +; CHECK-LABEL: loop32 +; CHECK: mvn +define void @loop32(i32* %a) { +entry: + br label %for.body + +for.body: + %i = phi i32 [ 0, %entry ], [ %inc, %for.body ] + %arrayidx = getelementptr inbounds i32, i32* %a, i32 %i + %x = load i32, i32* %arrayidx + %xn = xor i32 %x, -1 + store i32 %xn, i32* %arrayidx + %inc = add nuw nsw i32 %i, 1 + %exitcond = icmp eq i32 %inc, 10 + br i1 %exitcond, label %for.cond.cleanup, label %for.body + +for.cond.cleanup: + ret void +} + +; CHECK-LABEL: loop32_2 +; CHECK: mvn +; CHECK: mvn +define void @loop32_2(i32* %a, i32* %b) { +entry: + br label %for.body + +for.body: + %i = phi i32 [ 0, %entry ], [ %inc, %for.body ] + %arrayidx = getelementptr inbounds i32, i32* %a, i32 %i + %arrayidx2 = getelementptr inbounds i32, i32* %b, i32 %i + %x = load i32, i32* %arrayidx + %y = load i32, i32* %arrayidx2 + %xn = xor i32 %x, -1 + %yn = xor i32 %y, -1 + store i32 %xn, i32* %arrayidx + store i32 %yn, i32* %arrayidx2 + %inc = add nuw nsw i32 %i, 1 + %exitcond = icmp eq i32 %inc, 10 + br i1 %exitcond, label %for.cond.cleanup, label %for.body + +for.cond.cleanup: + ret void +} +