From d7b8b5c0b8751caf5b51622f2329b363ecabc267 Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Sat, 28 Nov 2020 13:41:39 +0100 Subject: Complete: Shift Left and Shift Right --- asm/intel64/encode.cpp | 57 ++++++++++++++++++++--- systemtest/mcc-execute.tests/exitcodes.exp | 1 + systemtest/mcc-execute.tests/test-shift-right.cpp | 3 ++ 3 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 systemtest/mcc-execute.tests/test-shift-right.cpp diff --git a/asm/intel64/encode.cpp b/asm/intel64/encode.cpp index 388639d..c02349c 100644 --- a/asm/intel64/encode.cpp +++ b/asm/intel64/encode.cpp @@ -195,13 +195,56 @@ std::vector> makeShiftLeftValue(const FlowGraph::Data& da index_t index { graph.scope()->indexOfData(data)}; std::vector> result; - result.push_back(makeOp("mov", Asm::Args{{Asm::Args::Register32("ecx"), Asm::Args::Mem32Ptr64("rbp", int32_t(index + 1) * -4)}})); // TODO: limit ecx to 0xff + result.push_back(makeOp("mov", Asm::Args{{Asm::Args::Register32("ecx"), Asm::Args::Mem32Ptr64("rbp", int32_t(index + 1) * -4)}})); + + // limit ecx to 0xff (for saving in cl) + result.push_back(makeOp("mov", Asm::Args{{Asm::Args::Register32("edx"), Asm::Args::Immediate32(0xff)}})); + result.push_back(makeOp("cmp", Asm::Args{{Asm::Args::Register32("ecx"), Asm::Args::Register32("edx")}})); + result.push_back(makeOp("cmova", Asm::Args{{Asm::Args::Register32("ecx"), Asm::Args::Register32("edx")}})); + result.push_back(makeOp("shl", Asm::Args{{Asm::Args::Register32("eax"), Asm::Args::Register8("cl")}})); return result; } else throw std::runtime_error("ICE: Unsupported type for operand data at shift left: "s + demangle(typeid(data_storage))); } +std::vector> makeShiftRightValue(const FlowGraph::Data& data, const FlowGraph::Graph& graph) +{ + if (data.type() != FlowGraph::DataType::Int) { + throw std::runtime_error("Bad type for operand: "s + std::to_string(int(data.type()))); + } + + if (!data.storage()) + throw std::runtime_error("ICE: Operand storage is 0"); + + auto& data_storage{*data.storage()}; + if (typeid(data_storage) == typeid(FlowGraph::Constant)) { + FlowGraph::Constant& value {dynamic_cast(data_storage)}; + if (value.value().size() < sizeof(uint32_t)) + throw std::runtime_error("ICE: Int data from operand needs at least 4 bytes, got "s + std::to_string(value.value().size())); + + uint32_t immediate = endian::from_little32(value.value()); + immediate = std::min(immediate, uint32_t(0xFF)); + + return {makeOp("shr", Asm::Args{{Asm::Args::Register32("eax"), Asm::Args::Immediate8(static_cast(immediate))}})}; + } else if (typeid(data_storage) == typeid(FlowGraph::TemporaryStorage)) { + //FlowGraph::TemporaryStorage& storage {dynamic_cast(data_storage)}; + + index_t index { graph.scope()->indexOfData(data)}; + std::vector> result; + result.push_back(makeOp("mov", Asm::Args{{Asm::Args::Register32("ecx"), Asm::Args::Mem32Ptr64("rbp", int32_t(index + 1) * -4)}})); + + // limit ecx to 0xff (for saving in cl) + result.push_back(makeOp("mov", Asm::Args{{Asm::Args::Register32("edx"), Asm::Args::Immediate32(0xff)}})); + result.push_back(makeOp("cmp", Asm::Args{{Asm::Args::Register32("ecx"), Asm::Args::Register32("edx")}})); + result.push_back(makeOp("cmova", Asm::Args{{Asm::Args::Register32("ecx"), Asm::Args::Register32("edx")}})); + + result.push_back(makeOp("shr", Asm::Args{{Asm::Args::Register32("eax"), Asm::Args::Register8("cl")}})); + return result; + } else + throw std::runtime_error("ICE: Unsupported type for operand data at shift right: "s + demangle(typeid(data_storage))); +} + } // namespace void Asm::toMachineCode(const FlowGraph::Graph& graph, Segment& segment) @@ -225,11 +268,9 @@ void Asm::toMachineCode(const FlowGraph::Graph& graph, Segment& segment) segment.push_back(makeStoreValue(operands[0], graph)); } else if (op.type() == FlowGraph::UnaryOperationType::LogicalNot) { segment.push_back(makeLoadValue(operands[1], graph)); - // TODO: cmp eax, 0 \n sete al \n movsx eax, al - segment.append(parseAsm("bsr eax")); // ZF=1 iff eax=0 - segment.append(parseAsm("lahf")); // ZF in AH bit 6 - segment.append(parseAsm("shr eax, 14")); // ZF in eax bit 0 - segment.append(parseAsm("and eax, 1")); // now, 0 or 1 is in eax, negated because of zero flag + segment.append(parseAsm("cmp eax, 0")); + segment.append(parseAsm("sete al")); + segment.append(parseAsm("movsx eax, al")); segment.push_back(makeStoreValue(operands[0], graph)); } else if (op.type() == FlowGraph::UnaryOperationType::Minus) { segment.push_back(makeLoadValue(operands[1], graph)); @@ -275,6 +316,10 @@ void Asm::toMachineCode(const FlowGraph::Graph& graph, Segment& segment) segment.push_back(makeLoadValue(operands[1], graph)); segment.append(makeShiftLeftValue(operands[2], graph)); segment.push_back(makeStoreValue(operands[0], graph)); + } else if (op.type() == FlowGraph::BinaryOperationType::ShiftRight) { + segment.push_back(makeLoadValue(operands[1], graph)); + segment.append(makeShiftRightValue(operands[2], graph)); + segment.push_back(makeStoreValue(operands[0], graph)); } else throw std::runtime_error("ICE: Asm: Unsupported binary operation type: "s + std::to_string(static_cast(op.type()))); diff --git a/systemtest/mcc-execute.tests/exitcodes.exp b/systemtest/mcc-execute.tests/exitcodes.exp index 1f84444..d4c68f6 100644 --- a/systemtest/mcc-execute.tests/exitcodes.exp +++ b/systemtest/mcc-execute.tests/exitcodes.exp @@ -10,4 +10,5 @@ runtest_exit_code "Parentheses Tree" "systemtest/mcc-execute.tests/test-parenthe runtest_exit_code "Parentheses Left" "systemtest/mcc-execute.tests/test-parentheses-left" 36 runtest_exit_code "Parentheses Right" "systemtest/mcc-execute.tests/test-parentheses-right" 36 runtest_exit_code "Shift Left" "systemtest/mcc-execute.tests/test-shift-left" 12 +runtest_exit_code "Shift Right" "systemtest/mcc-execute.tests/test-shift-right" 2 diff --git a/systemtest/mcc-execute.tests/test-shift-right.cpp b/systemtest/mcc-execute.tests/test-shift-right.cpp new file mode 100644 index 0000000..5974a22 --- /dev/null +++ b/systemtest/mcc-execute.tests/test-shift-right.cpp @@ -0,0 +1,3 @@ +int main() { + return 16 >> 3; +} -- cgit v1.2.3