Skip to content

Commit 84d4dc7

Browse files
committed
New low-level mutation: NegateXORReplacement
1 parent 0ec53c4 commit 84d4dc7

File tree

6 files changed

+159
-0
lines changed

6 files changed

+159
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//
2+
// Copyright 2020 Mull Project
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
//
16+
17+
#pragma once
18+
19+
#include "irm/IRMutation.h"
20+
21+
namespace irm {
22+
23+
class NegateXORReplacement : public IRMutation {
24+
public:
25+
NegateXORReplacement();
26+
bool canMutate(llvm::Instruction *instruction) override;
27+
void mutate(llvm::Instruction *instruction) override;
28+
29+
};
30+
31+
} // namespace irm

include/irm/irm.h

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "irm/Mutations/CmpInstPredicateReplacement.h"
2222
#include "irm/Mutations/ConstantReplacement.h"
2323
#include "irm/Mutations/IntrinsicReplacement.h"
24+
#include "irm/Mutations/NegateXORReplacement.h"
2425
#include "irm/Mutations/StoreValueReplacement.h"
2526
#include "irm/Mutations/SwapBinaryOperands.h"
2627
#include "irm/Mutations/VoidCallRemoval.h"

lib/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ set (SOURCES
55
ConstantReplacement.cpp
66
ConstValueConstructor.cpp
77
IntrinsicReplacement.cpp
8+
NegateXORReplacement.cpp
89
StoreValueReplacement.cpp
910
SwapBinaryOperands.cpp
1011
VoidCallRemoval.cpp

lib/NegateXORReplacement.cpp

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
//
2+
// Copyright 2020 Mull Project
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
//
16+
17+
#include "irm/Mutations/NegateXORReplacement.h"
18+
#include <llvm/IR/InstrTypes.h>
19+
20+
using namespace irm;
21+
22+
NegateXORReplacement::NegateXORReplacement() {}
23+
24+
bool NegateXORReplacement::canMutate(llvm::Instruction *instruction) {
25+
assert(instruction);
26+
if (instruction->getOpcode() != llvm::Instruction::Xor) {
27+
return false;
28+
}
29+
30+
return true;
31+
}
32+
33+
void NegateXORReplacement::mutate(llvm::Instruction *instruction) {
34+
assert(instruction);
35+
assert(canMutate(instruction));
36+
37+
/// Negating XOR means: "x ^ y" -> "x ^ !y".
38+
/// Our goal below is to add a NOT instruction to negate Y, however in LLVM,
39+
/// adding a "NOT x" instruction is implemented as doing "XOR x, true" (see the
40+
/// source code of llvm::BinaryOperator::CreateNot.
41+
///
42+
/// Example:
43+
/// entry:
44+
/// %xor = xor i1 true, false
45+
/// becomes:
46+
/// entry:
47+
/// %not = xor i1 false, true
48+
/// %xor = xor i1 true, %not
49+
auto rhs = instruction->getOperand(1);
50+
auto notInstruction = llvm::BinaryOperator::CreateNot(rhs, "not", instruction);
51+
instruction->setOperand(1, notInstruction);
52+
}

tests/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ set (SOURCES
55
Mutations/CmpInstPredicateReplacementTests.cpp
66
Mutations/ConstatnReplacementTests.cpp
77
Mutations/InstrinsicReplacementTests.cpp
8+
Mutations/NegateXORReplacementTests.cpp
89
Mutations/StoreValueReplacementTests.cpp
910
Mutations/SwapBinaryOperandsTests.cpp
1011
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
//
2+
// Copyright 2020 Mull Project
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
//
16+
17+
#include <gtest/gtest.h>
18+
#include <irm/irm.h>
19+
#include <llvm/IR/Module.h>
20+
#include "TestLLVMCompatibility.h"
21+
22+
using namespace irm;
23+
24+
TEST(NegateXORReplacement, canMutate) {
25+
using Mutator = NegateXORReplacement;
26+
27+
llvm::LLVMContext context;
28+
llvm::Module module("test", context);
29+
auto type = llvm::FunctionType::get(llvm::Type::getVoidTy(context), false);
30+
auto function = test_llvm_compat::internalFunction(type, "test", module);
31+
auto basicBlock = llvm::BasicBlock::Create(context, "entry", function);
32+
33+
auto op1 = llvm::ConstantInt::get(llvm::IntegerType::get(context, 1), 1, false);
34+
auto op2 = llvm::ConstantInt::get(llvm::IntegerType::get(context, 1), 0, false);
35+
auto xorInstruction = llvm::BinaryOperator::CreateXor(op1, op2, "xor", basicBlock);
36+
37+
Mutator mutator;
38+
ASSERT_TRUE(mutator.canMutate(xorInstruction));
39+
}
40+
41+
TEST(NegateXORReplacement, mutate) {
42+
using Mutator = NegateXORReplacement;
43+
44+
llvm::LLVMContext context;
45+
llvm::Module module("test", context);
46+
47+
auto type = llvm::FunctionType::get(llvm::Type::getVoidTy(context), false);
48+
auto function = test_llvm_compat::internalFunction(type, "test", module);
49+
auto basicBlock = llvm::BasicBlock::Create(context, "entry", function);
50+
51+
auto op1 = llvm::ConstantInt::get(llvm::IntegerType::get(context, 1), 1, false);
52+
auto op2 = llvm::ConstantInt::get(llvm::IntegerType::get(context, 1), 0, false);
53+
auto xorInstruction = llvm::BinaryOperator::CreateXor(op1, op2, "xor", basicBlock);
54+
55+
Mutator mutator;
56+
mutator.mutate(xorInstruction);
57+
58+
/// We expect to have 2 xor instructions instead of one. See the implementation
59+
/// details of NegateXorReplacement.mutate().
60+
/// Before:
61+
/// entry:
62+
/// %xor = xor i1 true, false
63+
///
64+
/// After:
65+
/// entry:
66+
/// %not = xor i1 false, true
67+
/// %xor = xor i1 true, %not
68+
ASSERT_EQ(xorInstruction->getOpcode(), llvm::Instruction::Xor);
69+
ASSERT_EQ(xorInstruction->getOperand(0), op1);
70+
ASSERT_EQ(xorInstruction->getOperand(1), xorInstruction->getPrevNode());
71+
ASSERT_EQ(xorInstruction->getPrevNode()->getOpcode(), llvm::Instruction::Xor);
72+
ASSERT_EQ(xorInstruction->getPrevNode()->getOperand(0), op2);
73+
}

0 commit comments

Comments
 (0)