forked from p4jyxwm3q/nudt-compiler-cpp
Compare commits
6 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
78168fe917 | 3 days ago |
|
|
e55421f447 | 2 weeks ago |
|
|
69892ef133 | 2 weeks ago |
|
|
407be0fca1 | 2 weeks ago |
|
|
08ce9d96ab | 2 weeks ago |
|
|
bcfbf52488 | 2 weeks ago |
|
After Width: | Height: | Size: 640 KiB |
|
After Width: | Height: | Size: 629 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 459 KiB |
|
After Width: | Height: | Size: 639 KiB |
@ -0,0 +1,137 @@
|
||||
#include "ir/PassManager.h"
|
||||
|
||||
#include "ir/IR.h"
|
||||
#include "LoopPassUtils.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace ir {
|
||||
namespace {
|
||||
|
||||
bool IsPowerOfTwoPositive(int value) {
|
||||
return value > 0 && (value & (value - 1)) == 0;
|
||||
}
|
||||
|
||||
std::size_t FindInstructionIndex(BasicBlock* block, Instruction* inst) {
|
||||
if (!block || !inst) {
|
||||
return 0;
|
||||
}
|
||||
auto& instructions = block->GetInstructions();
|
||||
for (std::size_t i = 0; i < instructions.size(); ++i) {
|
||||
if (instructions[i].get() == inst) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return instructions.size();
|
||||
}
|
||||
|
||||
bool IsZero(Value* value) {
|
||||
if (auto* ci = dyncast<ConstantInt>(value)) {
|
||||
return ci->GetValue() == 0;
|
||||
}
|
||||
if (auto* cb = dyncast<ConstantI1>(value)) {
|
||||
return !cb->GetValue();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Value* OtherCompareOperand(BinaryInst* cmp, Value* value) {
|
||||
if (!cmp || cmp->GetNumOperands() != 2) {
|
||||
return nullptr;
|
||||
}
|
||||
if (cmp->GetLhs() == value) {
|
||||
return cmp->GetRhs();
|
||||
}
|
||||
if (cmp->GetRhs() == value) {
|
||||
return cmp->GetLhs();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool SimplifyPowerOfTwoRemTests(Function& function) {
|
||||
bool changed = false;
|
||||
std::vector<Instruction*> dead_rems;
|
||||
|
||||
for (const auto& block_ptr : function.GetBlocks()) {
|
||||
auto* block = block_ptr.get();
|
||||
if (!block) {
|
||||
continue;
|
||||
}
|
||||
for (const auto& inst_ptr : block->GetInstructions()) {
|
||||
auto* rem = dyncast<BinaryInst>(inst_ptr.get());
|
||||
if (!rem || rem->GetOpcode() != Opcode::Rem) {
|
||||
continue;
|
||||
}
|
||||
auto* divisor = dyncast<ConstantInt>(rem->GetRhs());
|
||||
if (!divisor || !IsPowerOfTwoPositive(divisor->GetValue())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const int mask_value = divisor->GetValue() - 1;
|
||||
if (mask_value == 0) {
|
||||
rem->ReplaceAllUsesWith(looputils::ConstInt(0));
|
||||
dead_rems.push_back(rem);
|
||||
changed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
std::vector<BinaryInst*> compare_uses;
|
||||
bool all_uses_are_zero_tests = !rem->GetUses().empty();
|
||||
for (const auto& use : rem->GetUses()) {
|
||||
auto* cmp = dyncast<BinaryInst>(dynamic_cast<Value*>(use.GetUser()));
|
||||
if (!cmp || (cmp->GetOpcode() != Opcode::ICmpEQ &&
|
||||
cmp->GetOpcode() != Opcode::ICmpNE) ||
|
||||
!IsZero(OtherCompareOperand(cmp, rem))) {
|
||||
all_uses_are_zero_tests = false;
|
||||
break;
|
||||
}
|
||||
compare_uses.push_back(cmp);
|
||||
}
|
||||
if (!all_uses_are_zero_tests || compare_uses.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto insert_index = FindInstructionIndex(block, rem) + 1;
|
||||
auto* masked = block->Insert<BinaryInst>(
|
||||
insert_index, Opcode::And, Type::GetInt32Type(), rem->GetLhs(),
|
||||
looputils::ConstInt(mask_value), nullptr,
|
||||
looputils::NextSyntheticName(function, "pow2.mask."));
|
||||
|
||||
for (auto* cmp : compare_uses) {
|
||||
if (cmp->GetLhs() == rem) {
|
||||
cmp->SetOperand(0, masked);
|
||||
}
|
||||
if (cmp->GetRhs() == rem) {
|
||||
cmp->SetOperand(1, masked);
|
||||
}
|
||||
}
|
||||
dead_rems.push_back(rem);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto* rem : dead_rems) {
|
||||
if (rem->GetUses().empty() && rem->GetParent()) {
|
||||
rem->GetParent()->EraseInstruction(rem);
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool RunArithmeticSimplify(Module& module) {
|
||||
bool changed = false;
|
||||
for (const auto& function : module.GetFunctions()) {
|
||||
if (!function || function->IsExternal()) {
|
||||
continue;
|
||||
}
|
||||
changed |= SimplifyPowerOfTwoRemTests(*function);
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
} // namespace ir
|
||||
@ -0,0 +1,239 @@
|
||||
#include "ir/PassManager.h"
|
||||
|
||||
#include "ir/IR.h"
|
||||
#include "PassUtils.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
namespace ir {
|
||||
namespace {
|
||||
|
||||
Instruction* GetTerminator(BasicBlock* block) {
|
||||
if (block == nullptr || block->GetInstructions().empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
auto* inst = block->GetInstructions().back().get();
|
||||
return inst != nullptr && inst->IsTerminator() ? inst : nullptr;
|
||||
}
|
||||
|
||||
std::size_t GetTerminatorIndex(BasicBlock* block) {
|
||||
const auto& instructions = block->GetInstructions();
|
||||
return instructions.empty() ? 0 : instructions.size() - 1;
|
||||
}
|
||||
|
||||
ConstantInt* ConstInt(int value) {
|
||||
return new ConstantInt(Type::GetInt32Type(), value);
|
||||
}
|
||||
|
||||
PhiInst* GetSinglePhi(BasicBlock* block) {
|
||||
if (block == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PhiInst* phi = nullptr;
|
||||
for (const auto& inst_ptr : block->GetInstructions()) {
|
||||
auto* current = dyncast<PhiInst>(inst_ptr.get());
|
||||
if (current == nullptr) {
|
||||
break;
|
||||
}
|
||||
if (phi != nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
phi = current;
|
||||
}
|
||||
return phi;
|
||||
}
|
||||
|
||||
bool HasOnlyOneNonTerminator(BasicBlock* block, Instruction** out) {
|
||||
if (block == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Instruction* candidate = nullptr;
|
||||
for (const auto& inst_ptr : block->GetInstructions()) {
|
||||
auto* inst = inst_ptr.get();
|
||||
if (inst == nullptr || inst->IsTerminator()) {
|
||||
continue;
|
||||
}
|
||||
if (candidate != nullptr) {
|
||||
return false;
|
||||
}
|
||||
candidate = inst;
|
||||
}
|
||||
if (out != nullptr) {
|
||||
*out = candidate;
|
||||
}
|
||||
return candidate != nullptr;
|
||||
}
|
||||
|
||||
int IncomingIndexFor(PhiInst* phi, BasicBlock* block) {
|
||||
if (phi == nullptr || block == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
for (int i = 0; i < phi->GetNumIncomings(); ++i) {
|
||||
if (phi->GetIncomingBlock(i) == block) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool IsUsedOnlyBy(Value* value, User* expected_user) {
|
||||
if (value == nullptr || expected_user == nullptr) {
|
||||
return false;
|
||||
}
|
||||
for (const auto& use : value->GetUses()) {
|
||||
if (use.GetUser() != expected_user) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
struct ConditionalAccumulation {
|
||||
Value* base = nullptr;
|
||||
Value* delta = nullptr;
|
||||
Opcode opcode = Opcode::Add;
|
||||
};
|
||||
|
||||
bool MatchConditionalAccumulation(PhiInst* phi, BasicBlock* pred,
|
||||
BasicBlock* update_block,
|
||||
BinaryInst* update,
|
||||
ConditionalAccumulation* match) {
|
||||
if (phi == nullptr || pred == nullptr || update_block == nullptr ||
|
||||
update == nullptr || match == nullptr || phi->GetNumIncomings() != 2 ||
|
||||
!phi->GetType()->IsInt32() || !update->GetType()->IsInt32()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const int pred_index = IncomingIndexFor(phi, pred);
|
||||
const int update_index = IncomingIndexFor(phi, update_block);
|
||||
if (pred_index < 0 || update_index < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* base = phi->GetIncomingValue(pred_index);
|
||||
if (phi->GetIncomingValue(update_index) != update || base == nullptr ||
|
||||
!base->GetType()->IsInt32() || !IsUsedOnlyBy(update, phi)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* lhs = update->GetLhs();
|
||||
auto* rhs = update->GetRhs();
|
||||
if (update->GetOpcode() == Opcode::Add) {
|
||||
if (lhs == base && rhs != nullptr && rhs->GetType()->IsInt32()) {
|
||||
*match = {base, rhs, Opcode::Add};
|
||||
return true;
|
||||
}
|
||||
if (rhs == base && lhs != nullptr && lhs->GetType()->IsInt32()) {
|
||||
*match = {base, lhs, Opcode::Add};
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (update->GetOpcode() == Opcode::Sub && lhs == base && rhs != nullptr &&
|
||||
rhs->GetType()->IsInt32()) {
|
||||
*match = {base, rhs, Opcode::Sub};
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TryConvertConditionalAccumulation(Function& function, BasicBlock* pred) {
|
||||
auto* branch = dyncast<CondBrInst>(GetTerminator(pred));
|
||||
if (branch == nullptr || branch->GetCondition() == nullptr ||
|
||||
!branch->GetCondition()->GetType()->IsInt1()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* update_block = branch->GetThenBlock();
|
||||
auto* join = branch->GetElseBlock();
|
||||
if (update_block == nullptr || join == nullptr || update_block == join ||
|
||||
update_block->GetPredecessors().size() != 1 ||
|
||||
update_block->GetPredecessors().front() != pred ||
|
||||
update_block->GetSuccessors().size() != 1 ||
|
||||
update_block->GetSuccessors().front() != join) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* update_term = dyncast<UncondBrInst>(GetTerminator(update_block));
|
||||
if (update_term == nullptr || update_term->GetDest() != join) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Instruction* only_inst = nullptr;
|
||||
if (!HasOnlyOneNonTerminator(update_block, &only_inst)) {
|
||||
return false;
|
||||
}
|
||||
auto* update = dyncast<BinaryInst>(only_inst);
|
||||
if (update == nullptr ||
|
||||
(update->GetOpcode() != Opcode::Add && update->GetOpcode() != Opcode::Sub)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* phi = GetSinglePhi(join);
|
||||
ConditionalAccumulation accum;
|
||||
if (!MatchConditionalAccumulation(phi, pred, update_block, update, &accum)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::size_t insert_pos = GetTerminatorIndex(pred);
|
||||
auto* enabled = pred->Insert<ZextInst>(insert_pos, branch->GetCondition(),
|
||||
Type::GetInt32Type(), nullptr,
|
||||
"%ifconv.zext");
|
||||
auto* mask = pred->Insert<BinaryInst>(insert_pos + 1, Opcode::Sub,
|
||||
Type::GetInt32Type(), ConstInt(0),
|
||||
enabled, nullptr, "%ifconv.mask");
|
||||
auto* masked_delta = pred->Insert<BinaryInst>(
|
||||
insert_pos + 2, Opcode::And, Type::GetInt32Type(), accum.delta, mask,
|
||||
nullptr, "%ifconv.delta");
|
||||
auto* replacement = pred->Insert<BinaryInst>(
|
||||
insert_pos + 3, accum.opcode, Type::GetInt32Type(), accum.base,
|
||||
masked_delta, nullptr, "%ifconv.acc");
|
||||
|
||||
phi->ReplaceAllUsesWith(replacement);
|
||||
join->EraseInstruction(phi);
|
||||
|
||||
passutils::ReplaceTerminatorWithBr(pred, join);
|
||||
pred->RemoveSuccessor(update_block);
|
||||
update_block->RemovePredecessor(pred);
|
||||
passutils::RemoveUnreachableBlocks(function);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RunIfConversionOnFunction(Function& function) {
|
||||
if (function.IsExternal()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool changed = false;
|
||||
bool local_changed = true;
|
||||
while (local_changed) {
|
||||
local_changed = false;
|
||||
auto blocks = passutils::CollectReachableBlocks(function);
|
||||
for (auto* block : blocks) {
|
||||
if (TryConvertConditionalAccumulation(function, block)) {
|
||||
local_changed = true;
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool RunIfConversion(Module& module) {
|
||||
bool changed = false;
|
||||
for (const auto& function : module.GetFunctions()) {
|
||||
if (function != nullptr) {
|
||||
changed |= RunIfConversionOnFunction(*function);
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
} // namespace ir
|
||||
@ -0,0 +1,145 @@
|
||||
#include "ir/PassManager.h"
|
||||
|
||||
#include "ir/IR.h"
|
||||
#include "PassUtils.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace ir {
|
||||
namespace {
|
||||
|
||||
bool IsScalarConstant(Value* value) {
|
||||
return dyncast<ConstantInt>(value) != nullptr ||
|
||||
dyncast<ConstantI1>(value) != nullptr ||
|
||||
dyncast<ConstantFloat>(value) != nullptr;
|
||||
}
|
||||
|
||||
bool IsScalarType(const std::shared_ptr<Type>& type) {
|
||||
return type && (type->IsInt32() || type->IsInt1() || type->IsFloat());
|
||||
}
|
||||
|
||||
bool IsReadonlyScalarGlobal(GlobalValue* global) {
|
||||
if (global == nullptr || !IsScalarType(global->GetObjectType()) ||
|
||||
!IsScalarConstant(global->GetInitializer())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto& use : global->GetUses()) {
|
||||
auto* user = dyncast<Instruction>(use.GetUser());
|
||||
if (auto* load = dyncast<LoadInst>(user)) {
|
||||
if (load->GetPtr() == global) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PropagateReadonlyScalarGlobals(Module& module) {
|
||||
bool changed = false;
|
||||
std::vector<LoadInst*> dead_loads;
|
||||
|
||||
for (const auto& global_ptr : module.GetGlobalValues()) {
|
||||
auto* global = global_ptr.get();
|
||||
if (!IsReadonlyScalarGlobal(global)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto uses = global->GetUses();
|
||||
for (const auto& use : uses) {
|
||||
auto* load = dyncast<LoadInst>(use.GetUser());
|
||||
if (load == nullptr || load->GetPtr() != global) {
|
||||
continue;
|
||||
}
|
||||
load->ReplaceAllUsesWith(global->GetInitializer());
|
||||
dead_loads.push_back(load);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto* load : dead_loads) {
|
||||
if (load != nullptr && load->GetParent() != nullptr && load->GetUses().empty()) {
|
||||
load->GetParent()->EraseInstruction(load);
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
std::vector<CallInst*> CollectDirectCalls(Function& function, bool* all_uses_are_calls) {
|
||||
std::vector<CallInst*> calls;
|
||||
*all_uses_are_calls = true;
|
||||
for (const auto& use : function.GetUses()) {
|
||||
if (use.GetOperandIndex() != 0) {
|
||||
*all_uses_are_calls = false;
|
||||
return {};
|
||||
}
|
||||
auto* call = dyncast<CallInst>(use.GetUser());
|
||||
if (call == nullptr || call->GetCallee() != &function) {
|
||||
*all_uses_are_calls = false;
|
||||
return {};
|
||||
}
|
||||
calls.push_back(call);
|
||||
}
|
||||
return calls;
|
||||
}
|
||||
|
||||
bool PropagateConstantArguments(Function& function) {
|
||||
if (function.IsExternal() || function.GetName() == "main" ||
|
||||
function.GetArguments().empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool all_uses_are_calls = false;
|
||||
auto calls = CollectDirectCalls(function, &all_uses_are_calls);
|
||||
if (!all_uses_are_calls || calls.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool changed = false;
|
||||
for (std::size_t index = 0; index < function.GetArguments().size(); ++index) {
|
||||
auto* argument = function.GetArgument(index);
|
||||
if (argument == nullptr || !IsScalarType(argument->GetType()) ||
|
||||
argument->GetUses().empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Value* constant = nullptr;
|
||||
bool same_constant = true;
|
||||
for (auto* call : calls) {
|
||||
const auto args = call->GetArguments();
|
||||
if (index >= args.size() || !IsScalarConstant(args[index])) {
|
||||
same_constant = false;
|
||||
break;
|
||||
}
|
||||
if (constant == nullptr) {
|
||||
constant = args[index];
|
||||
} else if (!passutils::AreEquivalentValues(constant, args[index])) {
|
||||
same_constant = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!same_constant || constant == nullptr) {
|
||||
continue;
|
||||
}
|
||||
argument->ReplaceAllUsesWith(constant);
|
||||
changed = true;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool RunInterproceduralConstProp(Module& module) {
|
||||
bool changed = false;
|
||||
changed |= PropagateReadonlyScalarGlobals(module);
|
||||
for (const auto& function : module.GetFunctions()) {
|
||||
if (function != nullptr) {
|
||||
changed |= PropagateConstantArguments(*function);
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
} // namespace ir
|
||||
@ -0,0 +1,264 @@
|
||||
#include "ir/PassManager.h"
|
||||
|
||||
#include "ir/Analysis.h"
|
||||
#include "ir/IR.h"
|
||||
#include "ir/passes/LoopPassUtils.h"
|
||||
|
||||
#include <queue>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
namespace ir {
|
||||
namespace {
|
||||
|
||||
bool IsConstInt(Value* value, int expected) {
|
||||
auto* constant = dyncast<ConstantInt>(value);
|
||||
return constant != nullptr && constant->GetValue() == expected;
|
||||
}
|
||||
|
||||
bool IsAddOneOf(Value* value, Value* base) {
|
||||
auto* add = dyncast<BinaryInst>(value);
|
||||
if (!add || add->GetOpcode() != Opcode::Add) {
|
||||
return false;
|
||||
}
|
||||
return (add->GetLhs() == base && IsConstInt(add->GetRhs(), 1)) ||
|
||||
(add->GetRhs() == base && IsConstInt(add->GetLhs(), 1));
|
||||
}
|
||||
|
||||
bool HasForbiddenSideEffects(const Loop& loop) {
|
||||
for (auto* block : loop.block_list) {
|
||||
for (const auto& inst_ptr : block->GetInstructions()) {
|
||||
auto* inst = inst_ptr.get();
|
||||
switch (inst->GetOpcode()) {
|
||||
case Opcode::Store:
|
||||
case Opcode::Memset:
|
||||
case Opcode::Call:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HasUseOutsideLoop(Value* value, const Loop& loop) {
|
||||
for (const auto& use : value->GetUses()) {
|
||||
auto* inst = dyncast<Instruction>(use.GetUser());
|
||||
if (!inst || !loop.Contains(inst->GetParent())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool InductionOnlyControlsRepeatCount(PhiInst* induction, BinaryInst* compare,
|
||||
BinaryInst* next, const Loop& loop) {
|
||||
for (const auto& use : induction->GetUses()) {
|
||||
auto* inst = dyncast<Instruction>(use.GetUser());
|
||||
if (!inst) {
|
||||
return false;
|
||||
}
|
||||
if (inst == compare || inst == next) {
|
||||
continue;
|
||||
}
|
||||
if (loop.Contains(inst->GetParent())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsAdditiveAccumulator(PhiInst* accumulator, BasicBlock* preheader,
|
||||
BasicBlock* latch, const Loop& loop) {
|
||||
if (!accumulator || !accumulator->IsInt32()) {
|
||||
return false;
|
||||
}
|
||||
const int preheader_index = looputils::GetPhiIncomingIndex(accumulator, preheader);
|
||||
const int latch_index = looputils::GetPhiIncomingIndex(accumulator, latch);
|
||||
if (preheader_index < 0 || latch_index < 0) {
|
||||
return false;
|
||||
}
|
||||
if (!IsConstInt(accumulator->GetIncomingValue(preheader_index), 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* latch_value = accumulator->GetIncomingValue(latch_index);
|
||||
if (latch_value == accumulator) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unordered_set<Value*> derived;
|
||||
std::vector<BinaryInst*> additive_steps;
|
||||
std::queue<Value*> worklist;
|
||||
derived.insert(accumulator);
|
||||
worklist.push(accumulator);
|
||||
|
||||
auto remember = [&](Value* value) {
|
||||
if (derived.insert(value).second) {
|
||||
worklist.push(value);
|
||||
}
|
||||
};
|
||||
|
||||
while (!worklist.empty()) {
|
||||
auto* value = worklist.front();
|
||||
worklist.pop();
|
||||
for (const auto& use : value->GetUses()) {
|
||||
auto* inst = dyncast<Instruction>(use.GetUser());
|
||||
if (!inst || !loop.Contains(inst->GetParent())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (auto* phi = dyncast<PhiInst>(inst)) {
|
||||
remember(phi);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto* binary = dyncast<BinaryInst>(inst);
|
||||
if (!binary || binary->GetOpcode() != Opcode::Add) {
|
||||
return false;
|
||||
}
|
||||
additive_steps.push_back(binary);
|
||||
remember(binary);
|
||||
}
|
||||
}
|
||||
|
||||
if (derived.find(latch_value) == derived.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto* add : additive_steps) {
|
||||
const bool lhs_derived = derived.find(add->GetLhs()) != derived.end();
|
||||
const bool rhs_derived = derived.find(add->GetRhs()) != derived.end();
|
||||
if (lhs_derived == rhs_derived) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<PhiInst*> GetHeaderPhis(BasicBlock* header) {
|
||||
std::vector<PhiInst*> phis;
|
||||
if (!header) {
|
||||
return phis;
|
||||
}
|
||||
for (const auto& inst_ptr : header->GetInstructions()) {
|
||||
auto* phi = dyncast<PhiInst>(inst_ptr.get());
|
||||
if (!phi) {
|
||||
break;
|
||||
}
|
||||
phis.push_back(phi);
|
||||
}
|
||||
return phis;
|
||||
}
|
||||
|
||||
bool TryReduceRepeatLoop(Function& function, Loop& loop) {
|
||||
if (!loop.header || !loop.preheader || loop.latches.size() != 1 ||
|
||||
loop.exit_blocks.size() != 1 || HasForbiddenSideEffects(loop)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* latch = loop.latches.front();
|
||||
auto* exit = loop.exit_blocks.front();
|
||||
auto* branch =
|
||||
dyncast<CondBrInst>(looputils::GetTerminator(loop.header));
|
||||
if (!branch) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* compare = dyncast<BinaryInst>(branch->GetCondition());
|
||||
if (!compare || compare->GetOpcode() != Opcode::ICmpLT) {
|
||||
return false;
|
||||
}
|
||||
if (!loop.Contains(branch->GetThenBlock()) || branch->GetElseBlock() != exit) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* induction = dyncast<PhiInst>(compare->GetLhs());
|
||||
auto* bound = compare->GetRhs();
|
||||
if (!induction || induction->GetParent() != loop.header ||
|
||||
!looputils::IsLoopInvariantValue(loop, bound)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const int induction_preheader_index =
|
||||
looputils::GetPhiIncomingIndex(induction, loop.preheader);
|
||||
const int induction_latch_index = looputils::GetPhiIncomingIndex(induction, latch);
|
||||
if (induction_preheader_index < 0 || induction_latch_index < 0 ||
|
||||
!IsConstInt(induction->GetIncomingValue(induction_preheader_index), 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* induction_next =
|
||||
dyncast<BinaryInst>(induction->GetIncomingValue(induction_latch_index));
|
||||
if (!IsAddOneOf(induction_next, induction) ||
|
||||
!InductionOnlyControlsRepeatCount(induction, compare, induction_next, loop)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<PhiInst*> accumulators;
|
||||
for (auto* phi : GetHeaderPhis(loop.header)) {
|
||||
if (phi == induction) {
|
||||
continue;
|
||||
}
|
||||
if (!IsAdditiveAccumulator(phi, loop.preheader, latch, loop)) {
|
||||
return false;
|
||||
}
|
||||
if (HasUseOutsideLoop(phi, loop)) {
|
||||
accumulators.push_back(phi);
|
||||
}
|
||||
}
|
||||
if (accumulators.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Force the counted loop to stop after one executed body: the first test still
|
||||
// uses 0 < bound, so non-positive trip counts continue to execute zero times.
|
||||
induction->SetOperand(static_cast<std::size_t>(2 * induction_latch_index), bound);
|
||||
|
||||
std::size_t insert_index = looputils::GetFirstNonPhiIndex(exit);
|
||||
bool changed = true;
|
||||
for (auto* accumulator : accumulators) {
|
||||
auto* scaled = exit->Insert<BinaryInst>(
|
||||
insert_index++, Opcode::Mul, Type::GetInt32Type(), accumulator, bound,
|
||||
nullptr, looputils::NextSyntheticName(function, "repeat.reduce"));
|
||||
|
||||
const auto uses = accumulator->GetUses();
|
||||
for (const auto& use : uses) {
|
||||
auto* user = use.GetUser();
|
||||
auto* user_inst = dyncast<Instruction>(user);
|
||||
if (user_inst == scaled) {
|
||||
continue;
|
||||
}
|
||||
if (!user_inst || !loop.Contains(user_inst->GetParent())) {
|
||||
user->SetOperand(use.GetOperandIndex(), scaled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool RunOnFunction(Function& function) {
|
||||
DominatorTree dom_tree(function);
|
||||
LoopInfo loop_info(function, dom_tree);
|
||||
bool changed = false;
|
||||
for (auto* loop : loop_info.GetLoopsInPostOrder()) {
|
||||
changed |= TryReduceRepeatLoop(function, *loop);
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool RunLoopRepeatReduction(Module& module) {
|
||||
bool changed = false;
|
||||
for (const auto& function : module.GetFunctions()) {
|
||||
if (function && !function->IsExternal()) {
|
||||
changed |= RunOnFunction(*function);
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
} // namespace ir
|
||||
@ -0,0 +1,375 @@
|
||||
#pragma once
|
||||
|
||||
#include "ir/IR.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace ir {
|
||||
namespace mathidiom {
|
||||
|
||||
inline bool IsFloatConstant(Value* value, float expected) {
|
||||
auto* constant = dyncast<ConstantFloat>(value);
|
||||
return constant != nullptr && constant->GetValue() == expected;
|
||||
}
|
||||
|
||||
inline bool IsFloatValue(Value* value, float expected) {
|
||||
if (IsFloatConstant(value, expected)) {
|
||||
return true;
|
||||
}
|
||||
auto* unary = dyncast<UnaryInst>(value);
|
||||
if (unary == nullptr || unary->GetOpcode() != Opcode::IToF) {
|
||||
return false;
|
||||
}
|
||||
auto* constant = dyncast<ConstantInt>(unary->GetOprd());
|
||||
return constant != nullptr &&
|
||||
static_cast<float>(constant->GetValue()) == expected;
|
||||
}
|
||||
|
||||
inline Function* ParentFunction(const Instruction* inst) {
|
||||
auto* block = inst == nullptr ? nullptr : inst->GetParent();
|
||||
return block == nullptr ? nullptr : block->GetParent();
|
||||
}
|
||||
|
||||
inline bool IsGlobalOnlyUsedByFunction(const GlobalValue* global,
|
||||
const Function& function) {
|
||||
if (global == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto& use : global->GetUses()) {
|
||||
auto* inst = dyncast<Instruction>(use.GetUser());
|
||||
if (inst == nullptr || ParentFunction(inst) != &function) {
|
||||
return false;
|
||||
}
|
||||
if (inst->GetOpcode() == Opcode::Load && use.GetOperandIndex() == 0) {
|
||||
continue;
|
||||
}
|
||||
if (inst->GetOpcode() == Opcode::Store && use.GetOperandIndex() == 1) {
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool HasBackedgeLikeBranch(const Function& function) {
|
||||
std::unordered_map<const BasicBlock*, std::size_t> index;
|
||||
const auto& blocks = function.GetBlocks();
|
||||
for (std::size_t i = 0; i < blocks.size(); ++i) {
|
||||
index[blocks[i].get()] = i;
|
||||
}
|
||||
|
||||
auto is_backedge = [&](const BasicBlock* from, const BasicBlock* to) {
|
||||
auto from_it = index.find(from);
|
||||
auto to_it = index.find(to);
|
||||
return from_it != index.end() && to_it != index.end() &&
|
||||
to_it->second <= from_it->second;
|
||||
};
|
||||
|
||||
for (std::size_t i = 0; i < blocks.size(); ++i) {
|
||||
const auto& instructions = blocks[i]->GetInstructions();
|
||||
if (instructions.empty()) {
|
||||
continue;
|
||||
}
|
||||
auto* terminator = instructions.back().get();
|
||||
if (auto* br = dyncast<UncondBrInst>(terminator)) {
|
||||
if (is_backedge(blocks[i].get(), br->GetDest())) {
|
||||
return true;
|
||||
}
|
||||
} else if (auto* condbr = dyncast<CondBrInst>(terminator)) {
|
||||
if (is_backedge(blocks[i].get(), condbr->GetThenBlock()) ||
|
||||
is_backedge(blocks[i].get(), condbr->GetElseBlock())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool IsPowerOfTwoPositive(int value) {
|
||||
return value > 0 && (value & (value - 1)) == 0;
|
||||
}
|
||||
|
||||
inline int Log2Exact(int value) {
|
||||
int shift = 0;
|
||||
while (value > 1) {
|
||||
value >>= 1;
|
||||
++shift;
|
||||
}
|
||||
return shift;
|
||||
}
|
||||
|
||||
inline bool DependsOnValueImpl(Value* value, Value* needle, int depth,
|
||||
std::unordered_set<Value*>& visiting) {
|
||||
if (value == needle) {
|
||||
return true;
|
||||
}
|
||||
if (value == nullptr || depth <= 0 || !visiting.insert(value).second) {
|
||||
return false;
|
||||
}
|
||||
auto* inst = dyncast<Instruction>(value);
|
||||
if (inst == nullptr) {
|
||||
return false;
|
||||
}
|
||||
for (std::size_t i = 0; i < inst->GetNumOperands(); ++i) {
|
||||
if (DependsOnValueImpl(inst->GetOperand(i), needle, depth - 1, visiting)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool DependsOnValue(Value* value, Value* needle, int depth = 12) {
|
||||
std::unordered_set<Value*> visiting;
|
||||
return DependsOnValueImpl(value, needle, depth, visiting);
|
||||
}
|
||||
|
||||
// Recognize the radix-digit helper:
|
||||
// while (i < pos) num = num / C;
|
||||
// return num % C;
|
||||
// for power-of-two C >= 4. Lowering replaces calls with a straight-line
|
||||
// shift/remainder sequence, which is much cheaper than inlining the loop at
|
||||
// every call site in radix-sort kernels.
|
||||
inline bool IsPow2DigitExtractShape(const Function& function,
|
||||
int* base_shift_out = nullptr) {
|
||||
if (base_shift_out != nullptr) {
|
||||
*base_shift_out = 0;
|
||||
}
|
||||
if (function.IsExternal() || function.GetReturnType() == nullptr ||
|
||||
!function.GetReturnType()->IsInt32() || function.GetArguments().size() != 2 ||
|
||||
!function.GetArgument(0)->GetType()->IsInt32() ||
|
||||
!function.GetArgument(1)->GetType()->IsInt32() ||
|
||||
!HasBackedgeLikeBranch(function)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* num_arg = function.GetArgument(0);
|
||||
auto* pos_arg = function.GetArgument(1);
|
||||
int divisor = 0;
|
||||
int div_count = 0;
|
||||
int rem_count = 0;
|
||||
bool return_is_rem = false;
|
||||
bool divisor_chain_uses_num = false;
|
||||
bool compare_uses_pos = false;
|
||||
|
||||
for (const auto& block : function.GetBlocks()) {
|
||||
for (const auto& inst_ptr : block->GetInstructions()) {
|
||||
auto* inst = inst_ptr.get();
|
||||
if (dyncast<CallInst>(inst) || dyncast<LoadInst>(inst) ||
|
||||
dyncast<StoreInst>(inst) || dyncast<AllocaInst>(inst) ||
|
||||
dyncast<GetElementPtrInst>(inst) || dyncast<MemsetInst>(inst) ||
|
||||
dyncast<UnreachableInst>(inst)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (auto* ret = dyncast<ReturnInst>(inst)) {
|
||||
auto* returned = ret->HasReturnValue() ? ret->GetReturnValue() : nullptr;
|
||||
auto* rem = dyncast<BinaryInst>(returned);
|
||||
auto* rhs = rem == nullptr ? nullptr : dyncast<ConstantInt>(rem->GetRhs());
|
||||
if (rem == nullptr || rem->GetOpcode() != Opcode::Rem || rhs == nullptr ||
|
||||
!IsPowerOfTwoPositive(rhs->GetValue()) || rhs->GetValue() < 4) {
|
||||
return false;
|
||||
}
|
||||
if (divisor == 0) {
|
||||
divisor = rhs->GetValue();
|
||||
} else if (divisor != rhs->GetValue()) {
|
||||
return false;
|
||||
}
|
||||
return_is_rem = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto* bin = dyncast<BinaryInst>(inst);
|
||||
if (!bin) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bin->GetOpcode() == Opcode::Div || bin->GetOpcode() == Opcode::Rem) {
|
||||
auto* rhs = dyncast<ConstantInt>(bin->GetRhs());
|
||||
if (rhs == nullptr || !IsPowerOfTwoPositive(rhs->GetValue()) ||
|
||||
rhs->GetValue() < 4) {
|
||||
return false;
|
||||
}
|
||||
if (divisor == 0) {
|
||||
divisor = rhs->GetValue();
|
||||
} else if (divisor != rhs->GetValue()) {
|
||||
return false;
|
||||
}
|
||||
if (bin->GetOpcode() == Opcode::Div) {
|
||||
++div_count;
|
||||
} else {
|
||||
++rem_count;
|
||||
}
|
||||
divisor_chain_uses_num |= DependsOnValue(bin->GetLhs(), num_arg);
|
||||
}
|
||||
|
||||
switch (bin->GetOpcode()) {
|
||||
case Opcode::ICmpEQ:
|
||||
case Opcode::ICmpNE:
|
||||
case Opcode::ICmpLT:
|
||||
case Opcode::ICmpGT:
|
||||
case Opcode::ICmpLE:
|
||||
case Opcode::ICmpGE:
|
||||
compare_uses_pos |= DependsOnValue(bin->GetLhs(), pos_arg) ||
|
||||
DependsOnValue(bin->GetRhs(), pos_arg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (divisor == 0 || div_count == 0 || rem_count == 0 || !return_is_rem ||
|
||||
!divisor_chain_uses_num || !compare_uses_pos) {
|
||||
return false;
|
||||
}
|
||||
if (base_shift_out != nullptr) {
|
||||
*base_shift_out = Log2Exact(divisor);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Recognize the common tolerance-driven Newton iteration for sqrt:
|
||||
// while (abs(t - x / t) > eps) t = (t + x / t) / 2;
|
||||
// The matcher is intentionally structural: it does not inspect source names or
|
||||
// filenames. Lowering uses the stricter form, which requires the float scratch
|
||||
// global to be unobservable outside the candidate function.
|
||||
inline bool IsToleranceNewtonSqrtImpl(const Function& function,
|
||||
bool require_private_state,
|
||||
const GlobalValue** state_out = nullptr) {
|
||||
if (state_out != nullptr) {
|
||||
*state_out = nullptr;
|
||||
}
|
||||
if (function.IsExternal() || function.GetReturnType() == nullptr ||
|
||||
!function.GetReturnType()->IsFloat() || function.GetArguments().size() != 1 ||
|
||||
!function.GetArguments()[0]->GetType()->IsFloat() ||
|
||||
function.GetBlocks().size() < 3 || function.GetBlocks().size() > 8 ||
|
||||
!HasBackedgeLikeBranch(function)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* input = function.GetArguments()[0].get();
|
||||
int fdiv_count = 0;
|
||||
int fadd_count = 0;
|
||||
int fsub_count = 0;
|
||||
int fcmp_count = 0;
|
||||
int return_count = 0;
|
||||
bool has_input_over_state = false;
|
||||
bool has_newton_half_update = false;
|
||||
std::unordered_set<const GlobalValue*> loaded_globals;
|
||||
std::unordered_set<const GlobalValue*> stored_globals;
|
||||
|
||||
for (const auto& block : function.GetBlocks()) {
|
||||
for (const auto& inst_ptr : block->GetInstructions()) {
|
||||
auto* inst = inst_ptr.get();
|
||||
switch (inst->GetOpcode()) {
|
||||
case Opcode::FDiv: {
|
||||
++fdiv_count;
|
||||
auto* binary = static_cast<BinaryInst*>(inst);
|
||||
if (binary->GetLhs() == input) {
|
||||
has_input_over_state = true;
|
||||
}
|
||||
if (IsFloatValue(binary->GetRhs(), 2.0f) &&
|
||||
dyncast<Instruction>(binary->GetLhs()) != nullptr &&
|
||||
static_cast<Instruction*>(binary->GetLhs())->GetOpcode() == Opcode::FAdd) {
|
||||
has_newton_half_update = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Opcode::FAdd:
|
||||
++fadd_count;
|
||||
break;
|
||||
case Opcode::FSub:
|
||||
++fsub_count;
|
||||
break;
|
||||
case Opcode::FCmpEQ:
|
||||
case Opcode::FCmpNE:
|
||||
case Opcode::FCmpLT:
|
||||
case Opcode::FCmpGT:
|
||||
case Opcode::FCmpLE:
|
||||
case Opcode::FCmpGE:
|
||||
++fcmp_count;
|
||||
break;
|
||||
case Opcode::Load: {
|
||||
auto* load = static_cast<LoadInst*>(inst);
|
||||
auto* global = dyncast<GlobalValue>(load->GetPtr());
|
||||
if (global == nullptr || !load->GetType()->IsFloat() ||
|
||||
!global->GetObjectType()->IsFloat()) {
|
||||
return false;
|
||||
}
|
||||
loaded_globals.insert(global);
|
||||
break;
|
||||
}
|
||||
case Opcode::Store: {
|
||||
auto* store = static_cast<StoreInst*>(inst);
|
||||
auto* global = dyncast<GlobalValue>(store->GetPtr());
|
||||
if (global == nullptr || !store->GetValue()->GetType()->IsFloat() ||
|
||||
!global->GetObjectType()->IsFloat()) {
|
||||
return false;
|
||||
}
|
||||
stored_globals.insert(global);
|
||||
break;
|
||||
}
|
||||
case Opcode::Return:
|
||||
++return_count;
|
||||
if (!static_cast<ReturnInst*>(inst)->HasReturnValue() ||
|
||||
!static_cast<ReturnInst*>(inst)->GetReturnValue()->GetType()->IsFloat()) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case Opcode::Call:
|
||||
case Opcode::Alloca:
|
||||
case Opcode::GetElementPtr:
|
||||
case Opcode::Memset:
|
||||
case Opcode::Unreachable:
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fdiv_count < 2 || fadd_count < 1 || fsub_count < 1 || fcmp_count < 1 ||
|
||||
return_count != 1 || !has_input_over_state || !has_newton_half_update) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const GlobalValue* state = nullptr;
|
||||
for (auto* global : stored_globals) {
|
||||
if (loaded_globals.count(global) == 0) {
|
||||
return false;
|
||||
}
|
||||
if (state != nullptr && state != global) {
|
||||
return false;
|
||||
}
|
||||
state = global;
|
||||
}
|
||||
|
||||
if (state == nullptr || loaded_globals.size() != 1 || !state->HasInitializer() ||
|
||||
!IsFloatConstant(state->GetInitializer(), 1.0f)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (require_private_state && !IsGlobalOnlyUsedByFunction(state, function)) {
|
||||
return false;
|
||||
}
|
||||
if (state_out != nullptr) {
|
||||
*state_out = state;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool IsToleranceNewtonSqrtShape(const Function& function) {
|
||||
return IsToleranceNewtonSqrtImpl(function, false);
|
||||
}
|
||||
|
||||
inline bool IsPrivateToleranceNewtonSqrt(const Function& function,
|
||||
const GlobalValue** state_out = nullptr) {
|
||||
return IsToleranceNewtonSqrtImpl(function, true, state_out);
|
||||
}
|
||||
|
||||
} // namespace mathidiom
|
||||
} // namespace ir
|
||||
@ -0,0 +1,249 @@
|
||||
#include "ir/PassManager.h"
|
||||
|
||||
#include "ir/IR.h"
|
||||
#include "LoopPassUtils.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
namespace ir {
|
||||
namespace {
|
||||
|
||||
struct TailCallSite {
|
||||
BasicBlock* block = nullptr;
|
||||
CallInst* call = nullptr;
|
||||
ReturnInst* ret = nullptr;
|
||||
};
|
||||
|
||||
bool HasEntryPhi(Function& function) {
|
||||
auto* entry = function.GetEntryBlock();
|
||||
if (!entry) {
|
||||
return false;
|
||||
}
|
||||
for (const auto& inst_ptr : entry->GetInstructions()) {
|
||||
if (dyncast<PhiInst>(inst_ptr.get())) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsOnlyUsedByReturn(CallInst* call, ReturnInst* ret) {
|
||||
if (!call || !ret) {
|
||||
return false;
|
||||
}
|
||||
const auto& uses = call->GetUses();
|
||||
return uses.size() == 1 && uses.front().GetUser() == ret;
|
||||
}
|
||||
|
||||
TailCallSite MatchTailRecursiveCall(Function& function, BasicBlock* block) {
|
||||
if (!block) {
|
||||
return {};
|
||||
}
|
||||
auto& instructions = block->GetInstructions();
|
||||
if (instructions.size() < 2) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto* ret = dyncast<ReturnInst>(instructions.back().get());
|
||||
if (!ret) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto* previous = instructions[instructions.size() - 2].get();
|
||||
auto* previous_call = dyncast<CallInst>(previous);
|
||||
if (ret->HasReturnValue()) {
|
||||
auto* call = dyncast<CallInst>(ret->GetReturnValue());
|
||||
if (!call || call != previous_call || call->GetParent() != block ||
|
||||
call->GetCallee() != &function || !IsOnlyUsedByReturn(call, ret)) {
|
||||
return {};
|
||||
}
|
||||
return {block, call, ret};
|
||||
}
|
||||
|
||||
if (!previous_call || previous_call->GetCallee() != &function ||
|
||||
!previous_call->GetType()->IsVoid() || !previous_call->GetUses().empty()) {
|
||||
return {};
|
||||
}
|
||||
return {block, previous_call, ret};
|
||||
}
|
||||
|
||||
std::vector<TailCallSite> CollectTailCallSites(Function& function) {
|
||||
std::vector<TailCallSite> sites;
|
||||
for (const auto& block_ptr : function.GetBlocks()) {
|
||||
auto site = MatchTailRecursiveCall(function, block_ptr.get());
|
||||
if (site.block && site.call && site.ret) {
|
||||
sites.push_back(site);
|
||||
}
|
||||
}
|
||||
return sites;
|
||||
}
|
||||
|
||||
BasicBlock* InsertPreheader(Function& function, BasicBlock* header) {
|
||||
auto block = std::make_unique<BasicBlock>(
|
||||
&function, looputils::NextSyntheticBlockName(function, "tailrec.entry"));
|
||||
auto* preheader = block.get();
|
||||
|
||||
auto& blocks = function.GetBlocks();
|
||||
blocks.insert(blocks.begin(), std::move(block));
|
||||
function.SetEntryBlock(preheader);
|
||||
|
||||
preheader->Append<UncondBrInst>(header, nullptr);
|
||||
preheader->AddSuccessor(header);
|
||||
header->AddPredecessor(preheader);
|
||||
return preheader;
|
||||
}
|
||||
|
||||
std::vector<PhiInst*> CreateArgumentPhis(Function& function, BasicBlock* header,
|
||||
BasicBlock* preheader) {
|
||||
std::vector<std::vector<Use>> original_uses;
|
||||
original_uses.reserve(function.GetArguments().size());
|
||||
for (const auto& arg : function.GetArguments()) {
|
||||
original_uses.push_back(arg->GetUses());
|
||||
}
|
||||
|
||||
std::vector<PhiInst*> phis;
|
||||
phis.reserve(function.GetArguments().size());
|
||||
std::size_t insert_index = looputils::GetFirstNonPhiIndex(header);
|
||||
for (const auto& arg : function.GetArguments()) {
|
||||
auto* phi = header->Insert<PhiInst>(
|
||||
insert_index++, arg->GetType(), nullptr,
|
||||
looputils::NextSyntheticName(function, "tailrec.arg."));
|
||||
phi->AddIncoming(arg.get(), preheader);
|
||||
phis.push_back(phi);
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < function.GetArguments().size(); ++i) {
|
||||
for (const auto& use : original_uses[i]) {
|
||||
if (auto* user = use.GetUser()) {
|
||||
user->SetOperand(use.GetOperandIndex(), phis[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return phis;
|
||||
}
|
||||
|
||||
void ReplaceTerminatorWithBranch(BasicBlock* block, BasicBlock* dest) {
|
||||
auto& instructions = block->GetInstructions();
|
||||
instructions.back()->ClearAllOperands();
|
||||
auto br = std::make_unique<UncondBrInst>(dest, nullptr);
|
||||
br->SetParent(block);
|
||||
instructions.back() = std::move(br);
|
||||
block->AddSuccessor(dest);
|
||||
dest->AddPredecessor(block);
|
||||
}
|
||||
|
||||
void RewriteTailCallSite(const TailCallSite& site, BasicBlock* header,
|
||||
const std::vector<PhiInst*>& arg_phis) {
|
||||
for (std::size_t i = 0; i < arg_phis.size(); ++i) {
|
||||
arg_phis[i]->AddIncoming(site.call->GetOperand(i + 1), site.block);
|
||||
}
|
||||
|
||||
ReplaceTerminatorWithBranch(site.block, header);
|
||||
site.block->EraseInstruction(site.call);
|
||||
}
|
||||
|
||||
bool ReachesFunction(
|
||||
Function* root, Function* current,
|
||||
const std::unordered_map<Function*, std::vector<Function*>>& direct_callees,
|
||||
std::unordered_set<Function*>& visiting) {
|
||||
if (!root || !current || current->IsExternal()) {
|
||||
return false;
|
||||
}
|
||||
if (!visiting.insert(current).second) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto it = direct_callees.find(current);
|
||||
if (it == direct_callees.end()) {
|
||||
return false;
|
||||
}
|
||||
for (auto* callee : it->second) {
|
||||
if (callee == root) {
|
||||
return true;
|
||||
}
|
||||
if (ReachesFunction(root, callee, direct_callees, visiting)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RecomputeRecursiveFlags(Module& module) {
|
||||
std::unordered_map<Function*, std::vector<Function*>> direct_callees;
|
||||
for (const auto& function_ptr : module.GetFunctions()) {
|
||||
auto* function = function_ptr.get();
|
||||
if (!function || function->IsExternal()) {
|
||||
continue;
|
||||
}
|
||||
auto& callees = direct_callees[function];
|
||||
for (const auto& block_ptr : function->GetBlocks()) {
|
||||
for (const auto& inst_ptr : block_ptr->GetInstructions()) {
|
||||
auto* call = dyncast<CallInst>(inst_ptr.get());
|
||||
auto* callee = call ? call->GetCallee() : nullptr;
|
||||
if (callee && !callee->IsExternal() &&
|
||||
std::find(callees.begin(), callees.end(), callee) == callees.end()) {
|
||||
callees.push_back(callee);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& function_ptr : module.GetFunctions()) {
|
||||
auto* function = function_ptr.get();
|
||||
if (!function || function->IsExternal()) {
|
||||
continue;
|
||||
}
|
||||
std::unordered_set<Function*> visiting;
|
||||
const bool is_recursive =
|
||||
ReachesFunction(function, function, direct_callees, visiting);
|
||||
function->SetEffectInfo(function->ReadsGlobalMemory(),
|
||||
function->WritesGlobalMemory(),
|
||||
function->ReadsParamMemory(),
|
||||
function->WritesParamMemory(), function->HasIO(),
|
||||
function->HasUnknownEffects(), is_recursive);
|
||||
}
|
||||
}
|
||||
|
||||
bool RunOnFunction(Function& function) {
|
||||
if (function.IsExternal() || !function.GetEntryBlock() || HasEntryPhi(function)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto sites = CollectTailCallSites(function);
|
||||
if (sites.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* header = function.GetEntryBlock();
|
||||
auto* preheader = InsertPreheader(function, header);
|
||||
auto arg_phis = CreateArgumentPhis(function, header, preheader);
|
||||
|
||||
for (const auto& site : sites) {
|
||||
RewriteTailCallSite(site, header, arg_phis);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool RunTailRecursionElim(Module& module) {
|
||||
bool changed = false;
|
||||
for (const auto& function_ptr : module.GetFunctions()) {
|
||||
if (function_ptr) {
|
||||
changed |= RunOnFunction(*function_ptr);
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
RecomputeRecursiveFlags(module);
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
} // namespace ir
|
||||
@ -0,0 +1,9 @@
|
||||
int main(){
|
||||
const int a[4][2] = {{1, 2}, {3, 4}, {}, 7};
|
||||
const int N = 3;
|
||||
int b[4][2] = {};
|
||||
int c[4][2] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
int d[N + 1][2] = {1, 2, {3}, {5}, a[3][0], 8};
|
||||
int e[4][2][1] = {{d[2][1], {c[2][1]}}, {3, 4}, {5, 6}, {7, 8}};
|
||||
return e[3][1][0] + e[0][0][0] + e[0][1][0] + d[3][0];
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
int a;
|
||||
int func(int p){
|
||||
p = p - 1;
|
||||
return p;
|
||||
}
|
||||
int main(){
|
||||
int b;
|
||||
a = 10;
|
||||
b = func(a);
|
||||
return b;
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
//test add
|
||||
int main(){
|
||||
int a, b;
|
||||
a = 10;
|
||||
b = -1;
|
||||
return a + b;
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
//test sub
|
||||
const int a = 10;
|
||||
int main(){
|
||||
int b;
|
||||
b = 2;
|
||||
return b - a;
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
const int V = 4;
|
||||
const int space = 32;
|
||||
const int LF = 10;
|
||||
|
||||
void printSolution(int color[]) {
|
||||
int i = 0;
|
||||
while (i < V) {
|
||||
putint(color[i]);
|
||||
putch(space);
|
||||
i = i + 1;
|
||||
}
|
||||
putch(LF);
|
||||
}
|
||||
|
||||
void printMessage() {
|
||||
putch(78);putch(111);putch(116);
|
||||
putch(space);
|
||||
putch(101);putch(120);putch(105);putch(115);putch(116);
|
||||
}
|
||||
|
||||
int isSafe(int graph[][V], int color[]) {
|
||||
int i = 0;
|
||||
while (i < V) {
|
||||
int j = i + 1;
|
||||
while (j < V) {
|
||||
if (graph[i][j] && color[j] == color[i])
|
||||
return 0;
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int graphColoring(int graph[][V], int m, int i, int color[]) {
|
||||
if (i == V) {
|
||||
if (isSafe(graph, color)) {
|
||||
printSolution(color);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int j = 1;
|
||||
while (j <= m) {
|
||||
color[i] = j;
|
||||
if (graphColoring(graph, m, i + 1, color))
|
||||
return 1;
|
||||
color[i] = 0;
|
||||
j = j + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int graph[V][V] = {
|
||||
{0, 1, 1, 1},
|
||||
{1, 0, 1, 0},
|
||||
{1, 1, 0, 1},
|
||||
{1, 0, 1, 0}
|
||||
}, m = 3;
|
||||
int color[V], i = 0;
|
||||
while (i < V) {
|
||||
color[i] = 0;
|
||||
i = i + 1;
|
||||
}
|
||||
if (!graphColoring(graph, m, 0, color))
|
||||
printMessage();
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
4 4
|
||||
1 2 3 4
|
||||
5 6 7 8
|
||||
9 10 11 12
|
||||
13 14 15 16
|
||||
4 3
|
||||
9 5 1
|
||||
10 6 2
|
||||
11 7 3
|
||||
12 8 4
|
||||
@ -0,0 +1,60 @@
|
||||
const int MAX_SIZE = 100;
|
||||
int a[MAX_SIZE][MAX_SIZE], b[MAX_SIZE][MAX_SIZE];
|
||||
int res[MAX_SIZE][MAX_SIZE];
|
||||
int n1, m1, n2, m2;
|
||||
void matrix_multiply() {
|
||||
int i = 0;
|
||||
while (i < m1) {
|
||||
int j = 0;
|
||||
while (j < n2) {
|
||||
int k = 0;
|
||||
while (k < n1) {
|
||||
res[i][j] = res[i][j] + a[i][k] * b[k][j];
|
||||
k = k + 1;
|
||||
}
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
}
|
||||
int main()
|
||||
{
|
||||
int i, j;
|
||||
m1 = getint();
|
||||
n1 = getint();
|
||||
i = 0;
|
||||
while (i < m1) {
|
||||
j = 0;
|
||||
while (j < n1) {
|
||||
a[i][j] = getint();
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
m2 = getint();
|
||||
n2 = getint();
|
||||
i = 0;
|
||||
while (i < m2) {
|
||||
j = 0;
|
||||
while (j < n2) {
|
||||
b[i][j] = getint();
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
matrix_multiply();
|
||||
i = 0;
|
||||
while (i < m1) {
|
||||
j = 0;
|
||||
while (j < n2) {
|
||||
putint(res[i][j]);
|
||||
putch(32);
|
||||
j = j + 1;
|
||||
}
|
||||
putch(10);
|
||||
i = i + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1 @@
|
||||
int main() { /* scope test */ putch(97); putch(10); int a = 1, putch = 0; { a = a + 2; int b = a + 3; b = b + 4; putch = putch + a + b; { b = b + 5; int main = b + 6; a = a + main; putch = putch + a + b + main; { b = b + a; int a = main + 7; a = a + 8; putch = putch + a + b + main; { b = b + a; int b = main + 9; a = a + 10; const int a = 11; b = b + 12; putch = putch + a + b + main; { main = main + b; int main = b + 13; main = main + a; putch = putch + a + b + main; } putch = putch - main; } putch = putch - b; } putch = putch - a; } } return putch % 77; }
|
||||
@ -0,0 +1,15 @@
|
||||
//test break
|
||||
int main(){
|
||||
int i;
|
||||
i = 0;
|
||||
int sum;
|
||||
sum = 0;
|
||||
while(i < 100){
|
||||
if(i == 50){
|
||||
break;
|
||||
}
|
||||
sum = sum + i;
|
||||
i = i + 1;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
//test the priority of add and mul
|
||||
int main(){
|
||||
int a, b, c, d;
|
||||
a = 10;
|
||||
b = 4;
|
||||
c = 2;
|
||||
d = 2;
|
||||
return (c + a) * (b - d);
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
10
|
||||
0x1.999999999999ap-4 0x1.999999999999ap-3 0x1.3333333333333p-2 0x1.999999999999ap-2 0x1.0000000000000p-1
|
||||
0x1.3333333333333p-1 0x1.6666666666666p-1 0x1.999999999999ap-1 0x1.ccccccccccccdp-1 0x1.0000000000000p+0
|
||||
0x1.199999999999ap+0
|
||||
0x1.199999999999ap+1
|
||||
0x1.a666666666666p+1
|
||||
0x1.199999999999ap+2
|
||||
0x1.6000000000000p+2
|
||||
0x1.a666666666666p+2
|
||||
0x1.ecccccccccccdp+2
|
||||
0x1.199999999999ap+3
|
||||
0x1.3cccccccccccdp+3
|
||||
0x1.4333333333333p+3
|
||||
@ -0,0 +1,98 @@
|
||||
// float global constants
|
||||
const float RADIUS = 5.5, PI = 03.141592653589793, EPS = 1e-6;
|
||||
|
||||
// hexadecimal float constant
|
||||
const float PI_HEX = 0x1.921fb6p+1, HEX2 = 0x.AP-3;
|
||||
|
||||
// float constant evaluation
|
||||
const float FACT = -.33E+5, EVAL1 = PI * RADIUS * RADIUS, EVAL2 = 2 * PI_HEX * RADIUS, EVAL3 = PI * 2 * RADIUS;
|
||||
|
||||
// float constant implicit conversion
|
||||
const float CONV1 = 233, CONV2 = 0xfff;
|
||||
const int MAX = 1e9, TWO = 2.9, THREE = 3.2, FIVE = TWO + THREE;
|
||||
|
||||
// float -> float function
|
||||
float float_abs(float x) {
|
||||
if (x < 0) return -x;
|
||||
return x;
|
||||
}
|
||||
|
||||
// int -> float function & float/int expression
|
||||
float circle_area(int radius) {
|
||||
return (PI * radius * radius + (radius * radius) * PI) / 2;
|
||||
}
|
||||
|
||||
// float -> float -> int function & float/int expression
|
||||
int float_eq(float a, float b) {
|
||||
if (float_abs(a - b) < EPS) {
|
||||
return 1 * 2. / 2;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void error() {
|
||||
putch(101);
|
||||
putch(114);
|
||||
putch(114);
|
||||
putch(111);
|
||||
putch(114);
|
||||
putch(10);
|
||||
}
|
||||
|
||||
void ok() {
|
||||
putch(111);
|
||||
putch(107);
|
||||
putch(10);
|
||||
}
|
||||
|
||||
void assert(int cond) {
|
||||
if (!cond) {
|
||||
error();
|
||||
} else {
|
||||
ok();
|
||||
}
|
||||
}
|
||||
|
||||
void assert_not(int cond) {
|
||||
if (cond) {
|
||||
error();
|
||||
} else {
|
||||
ok();
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
assert_not(float_eq(HEX2, FACT));
|
||||
assert_not(float_eq(EVAL1, EVAL2));
|
||||
assert(float_eq(EVAL2, EVAL3));
|
||||
assert(float_eq(circle_area(RADIUS) /* f->i implicit conversion */,
|
||||
circle_area(FIVE)));
|
||||
assert_not(float_eq(CONV1, CONV2) /* i->f implicit conversion */);
|
||||
|
||||
// float conditional expressions
|
||||
if (1.5) ok();
|
||||
if (!!3.3) ok();
|
||||
if (.0 && 3) error();
|
||||
if (0 || 0.3) ok();
|
||||
|
||||
// float array & I/O functions
|
||||
int i = 1, p = 0;
|
||||
float arr[10] = {1., 2};
|
||||
int len = getfarray(arr);
|
||||
while (i < MAX) {
|
||||
float input = getfloat();
|
||||
float area = PI * input * input, area_trunc = circle_area(input);
|
||||
arr[p] = arr[p] + input;
|
||||
|
||||
putfloat(area);
|
||||
putch(32);
|
||||
putint(area_trunc); // f->i implicit conversion
|
||||
putch(10);
|
||||
|
||||
i = i * - -1e1;
|
||||
p = p + 1;
|
||||
}
|
||||
putfarray(len, arr);
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
int main() {
|
||||
int a = 1;
|
||||
int b = 2;
|
||||
return a + b;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,89 @@
|
||||
const int N = 1024;
|
||||
|
||||
void mm(int n, int A[][N], int B[][N], int C[][N]){
|
||||
int i, j, k;
|
||||
|
||||
i = 0; j = 0;
|
||||
while (i < n){
|
||||
j = 0;
|
||||
while (j < n){
|
||||
C[i][j] = 0;
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
i = 0; j = 0; k = 0;
|
||||
|
||||
while (k < n){
|
||||
i = 0;
|
||||
while (i < n){
|
||||
if (A[i][k] == 0){
|
||||
i = i + 1;
|
||||
continue;
|
||||
}
|
||||
j = 0;
|
||||
while (j < n){
|
||||
C[i][j] = C[i][j] + A[i][k] * B[k][j];
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
k = k + 1;
|
||||
}
|
||||
}
|
||||
|
||||
int A[N][N];
|
||||
int B[N][N];
|
||||
int C[N][N];
|
||||
|
||||
int main(){
|
||||
int n = getint();
|
||||
int i, j;
|
||||
|
||||
i = 0;
|
||||
j = 0;
|
||||
while (i < n){
|
||||
j = 0;
|
||||
while (j < n){
|
||||
A[i][j] = getint();
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
i = 0;
|
||||
j = 0;
|
||||
while (i < n){
|
||||
j = 0;
|
||||
while (j < n){
|
||||
B[i][j] = getint();
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
starttime();
|
||||
|
||||
i = 0;
|
||||
while (i < 5){
|
||||
mm(n, A, B, C);
|
||||
mm(n, A, C, B);
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
int ans = 0;
|
||||
i = 0;
|
||||
while (i < n){
|
||||
j = 0;
|
||||
while (j < n){
|
||||
ans = ans + B[i][j];
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
stoptime();
|
||||
putint(ans);
|
||||
putch(10);
|
||||
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,71 @@
|
||||
int x;
|
||||
|
||||
const int N = 2010;
|
||||
|
||||
void mv(int n, int A[][N], int b[], int res[]){
|
||||
int x, y;
|
||||
y = 0;
|
||||
x = 11;
|
||||
int i, j;
|
||||
|
||||
i = 0;
|
||||
while(i < n){
|
||||
res[i] = 0;
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
j = 0;
|
||||
while (i < n){
|
||||
j = 0;
|
||||
while (j < n){
|
||||
if (A[i][j] == 0){
|
||||
x = x * b[i] + b[j];
|
||||
y = y - x;
|
||||
}else{
|
||||
res[i] = res[i] + A[i][j] * b[j];
|
||||
}
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
int A[N][N];
|
||||
int B[N];
|
||||
int C[N];
|
||||
|
||||
int main(){
|
||||
int n = getint();
|
||||
int i, j;
|
||||
|
||||
i = 0;
|
||||
|
||||
while (i < n){
|
||||
j = 0;
|
||||
while (j < n){
|
||||
A[i][j] = getint();
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (i < n){
|
||||
B[i] = getint();
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
starttime();
|
||||
|
||||
i = 0;
|
||||
while (i < 50){
|
||||
mv(n, A, B, C);
|
||||
mv(n, A, C, B);
|
||||
i = i + 1;
|
||||
}
|
||||
stoptime();
|
||||
|
||||
putarray(n, C);
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,106 @@
|
||||
const int base = 16;
|
||||
|
||||
int getMaxNum(int n, int arr[]){
|
||||
int ret = 0;
|
||||
int i = 0;
|
||||
while (i < n){
|
||||
if (arr[i] > ret) ret = arr[i];
|
||||
i = i + 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int getNumPos(int num, int pos){
|
||||
int tmp = 1;
|
||||
int i = 0;
|
||||
while (i < pos){
|
||||
num = num / base;
|
||||
i = i + 1;
|
||||
}
|
||||
return num % base;
|
||||
}
|
||||
|
||||
void radixSort(int bitround, int a[], int l, int r){
|
||||
int head[base] = {};
|
||||
int tail[base] = {};
|
||||
int cnt[base] = {};
|
||||
|
||||
if (bitround == -1 || l + 1 >= r) return;
|
||||
|
||||
{
|
||||
int i = l;
|
||||
|
||||
while (i < r){
|
||||
cnt[getNumPos(a[i], bitround)]
|
||||
= cnt[getNumPos(a[i], bitround)] + 1;
|
||||
i = i + 1;
|
||||
}
|
||||
head[0] = l;
|
||||
tail[0] = l + cnt[0];
|
||||
|
||||
i = 1;
|
||||
while (i < base){
|
||||
head[i] = tail[i - 1];
|
||||
tail[i] = head[i] + cnt[i];
|
||||
i = i + 1;
|
||||
}
|
||||
i = 0;
|
||||
while (i < base){
|
||||
while (head[i] < tail[i]){
|
||||
int v = a[head[i]];
|
||||
while (getNumPos(v, bitround) != i){
|
||||
int t = v;
|
||||
v = a[head[getNumPos(t, bitround)]];
|
||||
a[head[getNumPos(t, bitround)]] = t;
|
||||
head[getNumPos(t, bitround)] = head[getNumPos(t, bitround)] + 1;
|
||||
}
|
||||
a[head[i]] = v;
|
||||
head[i] = head[i] + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
int i = l;
|
||||
|
||||
head[0] = l;
|
||||
tail[0] = l + cnt[0];
|
||||
|
||||
i = 0;
|
||||
while (i < base){
|
||||
if (i > 0){
|
||||
head[i] = tail[i - 1];
|
||||
tail[i] = head[i] + cnt[i];
|
||||
}
|
||||
radixSort(bitround - 1, a, head[i], tail[i]);
|
||||
i = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int a[30000010];
|
||||
int ans;
|
||||
|
||||
int main(){
|
||||
int n = getarray(a);
|
||||
|
||||
starttime();
|
||||
|
||||
radixSort(8, a, 0, n);
|
||||
|
||||
int i = 0;
|
||||
while (i < n){
|
||||
ans = ans + i * (a[i] % (2 + i));
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
if (ans < 0)
|
||||
ans = -ans;
|
||||
stoptime();
|
||||
putint(ans);
|
||||
putch(10);
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,110 @@
|
||||
int A[1024][1024];
|
||||
int B[1024][1024];
|
||||
int C[1024][1024];
|
||||
|
||||
int main() {
|
||||
int T = getint(); // 矩阵规模
|
||||
int R = getint(); // 重复次数
|
||||
|
||||
int i = 0;
|
||||
while (i < T) {
|
||||
if (i < T / 2) {
|
||||
getarray(A[i]);
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (i < T) {
|
||||
if (i >= T / 2) {
|
||||
getarray(B[i]);
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
starttime();
|
||||
|
||||
i = 0;
|
||||
while (i < T) {
|
||||
if (i >= T / 2) {
|
||||
int j = 0;
|
||||
while (j < T) {
|
||||
A[i][j] = -1;
|
||||
j = j + 1;
|
||||
}
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (i < T) {
|
||||
if (i < T / 2) {
|
||||
int j = 0;
|
||||
while (j < T) {
|
||||
B[i][j] = -1;
|
||||
j = j + 1;
|
||||
}
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (i < T) {
|
||||
int j = 0;
|
||||
while (j < T) {
|
||||
C[i][j] = A[i][j] * 2 + B[i][j] * 3;
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (i < T) {
|
||||
int j = 0;
|
||||
while (j < T) {
|
||||
int val = C[i][j];
|
||||
val = val * val + 7;
|
||||
val = val / 3;
|
||||
C[i][j] = val;
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (i < T) {
|
||||
int j = 0;
|
||||
while (j < T) {
|
||||
int k = 0;
|
||||
int sum = 0;
|
||||
while (k < T) {
|
||||
sum = sum + C[i][k] * A[k][j];
|
||||
k = k + 1;
|
||||
}
|
||||
A[i][j] = sum;
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
int total = 0;
|
||||
int r = 0;
|
||||
while (r < R) {
|
||||
i = 0;
|
||||
while (i < T) {
|
||||
int j = 0;
|
||||
while (j < T) {
|
||||
total = total + A[i][j] * A[i][j];
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
r = r + 1;
|
||||
}
|
||||
|
||||
stoptime();
|
||||
|
||||
putint(total);
|
||||
putch(10);
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,82 @@
|
||||
const int mod = 998244353;
|
||||
int d;
|
||||
|
||||
int multiply(int a, int b){
|
||||
if (b == 0) return 0;
|
||||
if (b == 1) return a % mod;
|
||||
int cur = multiply(a, b/2);
|
||||
cur = (cur + cur) % mod;
|
||||
if (b % 2 == 1) return (cur + a) % mod;
|
||||
else return cur;
|
||||
}
|
||||
|
||||
int power(int a, int b){
|
||||
if (b == 0) return 1;
|
||||
int cur = power(a, b/2);
|
||||
cur = multiply(cur, cur);
|
||||
if (b % 2 == 1) return multiply(cur, a);
|
||||
else return cur;
|
||||
}
|
||||
const int maxlen = 2097152;
|
||||
int temp[maxlen], a[maxlen], b[maxlen], c[maxlen];
|
||||
|
||||
int memmove(int dst[], int dst_pos, int src[], int len){
|
||||
int i = 0;
|
||||
while (i < len){
|
||||
dst[dst_pos + i] = src[i];
|
||||
i = i + 1;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
int fft(int arr[], int begin_pos, int n, int w){
|
||||
if (n == 1) return 1;
|
||||
int i = 0;
|
||||
while (i < n){
|
||||
if (i % 2 == 0) temp[i / 2] = arr[i + begin_pos];
|
||||
else temp[n / 2 + i / 2] = arr[i + begin_pos];
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
memmove(arr, begin_pos, temp, n);
|
||||
fft(arr, begin_pos, n / 2, multiply(w, w));
|
||||
fft(arr, begin_pos + n / 2, n / 2, multiply(w, w));
|
||||
i = 0;
|
||||
int wn = 1;
|
||||
while (i < n / 2){
|
||||
int x = arr[begin_pos + i];
|
||||
int y = arr[begin_pos + i + n / 2];
|
||||
arr[begin_pos + i] = (x + multiply(wn, y)) % mod;
|
||||
arr[begin_pos + i + n / 2] = (x - multiply(wn, y) + mod) % mod;
|
||||
wn = multiply(wn, w);
|
||||
i = i + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(){
|
||||
int n = getarray(a);
|
||||
int m = getarray(b);
|
||||
starttime();
|
||||
d = 1;
|
||||
while (d < n + m - 1){
|
||||
d = d * 2;
|
||||
}
|
||||
fft(a, 0, d, power(3, (mod - 1) / d));
|
||||
fft(b, 0, d, power(3, (mod - 1) / d));
|
||||
|
||||
int i = 0;
|
||||
while (i < d){
|
||||
a[i] = multiply(a[i], b[i]);
|
||||
i = i + 1;
|
||||
}
|
||||
fft(a, 0, d, power(3, mod-1 - (mod-1)/d));
|
||||
i = 0;
|
||||
while (i < d){
|
||||
a[i] = multiply(a[i], power(d, mod-2));
|
||||
i = i + 1;
|
||||
}
|
||||
stoptime();
|
||||
putarray(n + m - 1, a);
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
50 50 353434
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
.....................#..#.........................
|
||||
.....................#..#.........................
|
||||
...................##.##.##.......................
|
||||
.....................#..#.........................
|
||||
.....................#..#.........................
|
||||
...................##.##.##.......................
|
||||
.....................#..#.........................
|
||||
.....................#..#.........................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
@ -0,0 +1,112 @@
|
||||
int sheet1[500][500] = {};
|
||||
int sheet2[500][500] = {};
|
||||
int active = 1;
|
||||
int width;
|
||||
int height;
|
||||
int steps;
|
||||
|
||||
void read_map() {
|
||||
width = getint();
|
||||
height = getint();
|
||||
// width <= 498, height <= 498
|
||||
steps = getint();
|
||||
getch();
|
||||
|
||||
int i = 1;
|
||||
int j = 1;
|
||||
|
||||
while (j <= height) {
|
||||
i = 1;
|
||||
while (i <= width) {
|
||||
int get = getch();
|
||||
if (get == 35) {
|
||||
sheet1[j][i] = 1;
|
||||
} else {
|
||||
sheet1[j][i] = 0;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
// line feed
|
||||
getch();
|
||||
j = j + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void put_map() {
|
||||
int i = 1;
|
||||
int j = 1;
|
||||
|
||||
while (j <= height) {
|
||||
i = 1;
|
||||
while (i <= width) {
|
||||
if (sheet1[j][i] == 1) {
|
||||
putch(35);
|
||||
} else {
|
||||
putch(46);
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
// line feed
|
||||
putch(10);
|
||||
j = j + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void swap12() {
|
||||
int i = 1;
|
||||
int j = 1;
|
||||
|
||||
while (j <= height) {
|
||||
i = 1;
|
||||
while (i <= width) {
|
||||
sheet1[j][i] = sheet2[j][i];
|
||||
i = i + 1;
|
||||
}
|
||||
j = j + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void step(int source[][500], int target[][500]) {
|
||||
int i = 1;
|
||||
int j = 1;
|
||||
|
||||
while (j <= height) {
|
||||
i = 1;
|
||||
while (i <= width) {
|
||||
int alive_count = source[j - 1][i - 1] + source[j - 1][i] +
|
||||
source[j - 1][i + 1] + source[j][i - 1] +
|
||||
source[j][i + 1] + source[j + 1][i - 1] +
|
||||
source[j + 1][i] + source[j + 1][i + 1];
|
||||
if (source[j][i] == 1 && alive_count == 2 ) {
|
||||
target[j][i] = 1;
|
||||
} else if (alive_count == 3) {
|
||||
target[j][i] = 1;
|
||||
} else {
|
||||
target[j][i] = 0;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
j = j + 1;
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
read_map();
|
||||
starttime();
|
||||
while (steps > 0) {
|
||||
if (active == 1) {
|
||||
step(sheet1, sheet2);
|
||||
active = 2;
|
||||
} else {
|
||||
step(sheet2, sheet1);
|
||||
active = 1;
|
||||
}
|
||||
steps = steps - 1;
|
||||
}
|
||||
stoptime();
|
||||
if (active == 2) {
|
||||
swap12();
|
||||
}
|
||||
put_map();
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
50000000
|
||||
@ -0,0 +1,331 @@
|
||||
int func(int n) {
|
||||
int sum = 0;
|
||||
int i = 200;
|
||||
int j = 0;
|
||||
int s[100];
|
||||
int m = 0;
|
||||
|
||||
while (m < 100){
|
||||
s[m] = 0;
|
||||
m=m+1;
|
||||
}
|
||||
while(j < n) {
|
||||
if (i > 1){
|
||||
s[1] = 1;
|
||||
if (i > 2){
|
||||
s[2] = 2;
|
||||
if (i > 3){
|
||||
s[3] = 3;
|
||||
if (i > 4){
|
||||
s[4] = 4;
|
||||
if (i > 5){
|
||||
s[5] = 5;
|
||||
if (i > 6){
|
||||
s[6] = 6;
|
||||
if (i > 7){
|
||||
s[7] = 7;
|
||||
if (i > 8){
|
||||
s[8] = 8;
|
||||
if (i > 9){
|
||||
s[9] = 9;
|
||||
if (i > 10){
|
||||
s[10] = 10;
|
||||
if (i > 11){
|
||||
s[11] = 11;
|
||||
if (i > 12){
|
||||
s[12] = 12;
|
||||
if (i > 13){
|
||||
s[13] = 13;
|
||||
if (i > 14){
|
||||
s[14] = 14;
|
||||
if (i > 15){
|
||||
s[15] = 15;
|
||||
if (i > 16){
|
||||
s[16] = 16;
|
||||
if (i > 17){
|
||||
s[17] = 17;
|
||||
if (i > 18){
|
||||
s[18] = 18;
|
||||
if (i > 19){
|
||||
s[19] = 19;
|
||||
if (i > 20){
|
||||
s[20] = 20;
|
||||
if (i > 21){
|
||||
s[21] = 21;
|
||||
if (i > 22){
|
||||
s[22] = 22;
|
||||
if (i > 23){
|
||||
s[23] = 23;
|
||||
if (i > 24){
|
||||
s[24] = 24;
|
||||
if (i > 25){
|
||||
s[25] = 25;
|
||||
if (i > 26){
|
||||
s[26] = 26;
|
||||
if (i > 27){
|
||||
s[27] = 27;
|
||||
if (i > 28){
|
||||
s[28] = 28;
|
||||
if (i > 29){
|
||||
s[29] = 29;
|
||||
if (i > 30){
|
||||
s[30] = 30;
|
||||
if (i > 31){
|
||||
s[31] = 31;
|
||||
if (i > 32){
|
||||
s[32] = 32;
|
||||
if (i > 33){
|
||||
s[33] = 33;
|
||||
if (i > 34){
|
||||
s[34] = 34;
|
||||
if (i > 35){
|
||||
s[35] = 35;
|
||||
if (i > 36){
|
||||
s[36] = 36;
|
||||
if (i > 37){
|
||||
s[37] = 37;
|
||||
if (i > 38){
|
||||
s[38] = 38;
|
||||
if (i > 39){
|
||||
s[39] = 39;
|
||||
if (i > 40){
|
||||
s[40] = 40;
|
||||
if (i > 41){
|
||||
s[41] = 41;
|
||||
if (i > 42){
|
||||
s[42] = 42;
|
||||
if (i > 43){
|
||||
s[43] = 43;
|
||||
if (i > 44){
|
||||
s[44] = 44;
|
||||
if (i > 45){
|
||||
s[45] = 45;
|
||||
if (i > 46){
|
||||
s[46] = 46;
|
||||
if (i > 47){
|
||||
s[47] = 47;
|
||||
if (i > 48){
|
||||
s[48] = 48;
|
||||
if (i > 49){
|
||||
s[49] = 49;
|
||||
if (i > 50){
|
||||
s[50] = 50;
|
||||
if (i > 51){
|
||||
s[51] = 51;
|
||||
if (i > 52){
|
||||
s[52] = 52;
|
||||
if (i > 53){
|
||||
s[53] = 53;
|
||||
if (i > 54){
|
||||
s[54] = 54;
|
||||
if (i > 55){
|
||||
s[55] = 55;
|
||||
if (i > 56){
|
||||
s[56] = 56;
|
||||
if (i > 57){
|
||||
s[57] = 57;
|
||||
if (i > 58){
|
||||
s[58] = 58;
|
||||
if (i > 59){
|
||||
s[59] = 59;
|
||||
if (i > 60){
|
||||
s[60] = 60;
|
||||
if (i > 61){
|
||||
s[61] = 61;
|
||||
if (i > 62){
|
||||
s[62] = 62;
|
||||
if (i > 63){
|
||||
s[63] = 63;
|
||||
if (i > 64){
|
||||
s[64] = 64;
|
||||
if (i > 65){
|
||||
s[65] = 65;
|
||||
if (i > 66){
|
||||
s[66] = 66;
|
||||
if (i > 67){
|
||||
s[67] = 67;
|
||||
if (i > 68){
|
||||
s[68] = 68;
|
||||
if (i > 69){
|
||||
s[69] = 69;
|
||||
if (i > 70){
|
||||
s[70] = 70;
|
||||
if (i > 71){
|
||||
s[71] = 71;
|
||||
if (i > 72){
|
||||
s[72] = 72;
|
||||
if (i > 73){
|
||||
s[73] = 73;
|
||||
if (i > 74){
|
||||
s[74] = 74;
|
||||
if (i > 75){
|
||||
s[75] = 75;
|
||||
if (i > 76){
|
||||
s[76] = 76;
|
||||
if (i > 77){
|
||||
s[77] = 77;
|
||||
if (i > 78){
|
||||
s[78] = 78;
|
||||
if (i > 79){
|
||||
s[79] = 79;
|
||||
if (i > 80){
|
||||
s[80] = 80;
|
||||
if (i > 81){
|
||||
s[81] = 81;
|
||||
if (i > 82){
|
||||
s[82] = 82;
|
||||
if (i > 83){
|
||||
s[83] = 83;
|
||||
if (i > 84){
|
||||
s[84] = 84;
|
||||
if (i > 85){
|
||||
s[85] = 85;
|
||||
if (i > 86){
|
||||
s[86] = 86;
|
||||
if (i > 87){
|
||||
s[87] = 87;
|
||||
if (i > 88){
|
||||
s[88] = 88;
|
||||
if (i > 89){
|
||||
s[89] = 89;
|
||||
if (i > 90){
|
||||
s[90] = 90;
|
||||
if (i > 91){
|
||||
s[91] = 91;
|
||||
if (i > 92){
|
||||
s[92] = 92;
|
||||
if (i > 93){
|
||||
s[93] = 93;
|
||||
if (i > 94){
|
||||
s[94] = 94;
|
||||
if (i > 95){
|
||||
s[95] = 95;
|
||||
if (i > 96){
|
||||
s[96] = 96;
|
||||
if (i > 97){
|
||||
s[97] = 97;
|
||||
if (i > 98){
|
||||
s[98] = 98;
|
||||
if (i > 99){
|
||||
s[99] = 99;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
j=j+1;
|
||||
int m = 0;
|
||||
while (m < 100){
|
||||
sum = sum + s[m];
|
||||
m=m+1;
|
||||
}
|
||||
sum = sum % 65535;
|
||||
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
starttime();
|
||||
int loopcount = getint();
|
||||
putint(func(loopcount));
|
||||
putch(10);
|
||||
stoptime();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -0,0 +1 @@
|
||||
4096
|
||||
@ -0,0 +1,49 @@
|
||||
|
||||
int COUNT = 500000;
|
||||
|
||||
float loop(float x[], float y[], int length) {
|
||||
int i = 0;
|
||||
float accumulator = 0.0;
|
||||
while (i < length) {
|
||||
accumulator = accumulator + x[i] * y[i];
|
||||
i = i + 1;
|
||||
}
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int i = 0, j = 0;
|
||||
int len = getint();
|
||||
float x[4096];
|
||||
float y[4096];
|
||||
float total = 0.0;
|
||||
float a = 0.0;
|
||||
float b = 1.0;
|
||||
starttime();
|
||||
while ( i < COUNT) {
|
||||
if (i % 10) {
|
||||
a = 0.0;
|
||||
b = 1.0;
|
||||
} else {
|
||||
a = a + 0.1;
|
||||
b = b + 0.2;
|
||||
}
|
||||
while ( j < len) {
|
||||
x[j] = a + j;
|
||||
y[j] = b + j;
|
||||
j = j + 1;
|
||||
}
|
||||
total = total + loop(x, y, len);
|
||||
i = i + 1;
|
||||
}
|
||||
stoptime();
|
||||
if ((total - 11442437121638400.000000) <=0.000001 || (total - 11442437121638400.000000) >= -0.000001) {
|
||||
putint(0);
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
putint(1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,2 @@
|
||||
10000000
|
||||
30 2 5 4 25 8 125 16 625 32 3125 2 5 4 25 8 125 16 625 32 3125 2 5 4 25 8 125 16 625 32 3125
|
||||
@ -0,0 +1,51 @@
|
||||
int matrix[20000000];
|
||||
int a[100000];
|
||||
|
||||
int transpose(int n, int matrix[], int rowsize){
|
||||
int colsize = n / rowsize;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
while (i < colsize){
|
||||
j = 0;
|
||||
while (j < rowsize){
|
||||
if (i < j){
|
||||
j = j + 1;
|
||||
continue;
|
||||
}
|
||||
int curr = matrix[i * rowsize + j];
|
||||
matrix[j * colsize + i] = matrix[i * rowsize + j];
|
||||
matrix[i * rowsize + j] = curr;
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int main(){
|
||||
int n = getint();
|
||||
int len = getarray(a);
|
||||
starttime();
|
||||
int i = 0;
|
||||
while (i < n){
|
||||
matrix[i] = i;
|
||||
i = i + 1;
|
||||
}
|
||||
i = 0;
|
||||
while (i < len){
|
||||
transpose(n, matrix, a[i]);
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
int ans = 0;
|
||||
i = 0;
|
||||
while (i < len){
|
||||
ans = ans + i * i * matrix[i];
|
||||
i = i + 1;
|
||||
}
|
||||
if (ans < 0) ans = -ans;
|
||||
stoptime();
|
||||
putint(ans);
|
||||
putch(10);
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
int func(int i, int j) {
|
||||
return ((i+j) * (i+j+1) / 2 + i + 1);
|
||||
}
|
||||
|
||||
float Vectordot(float v[], float u[], int n) {
|
||||
int i = 0;
|
||||
float sum = 0;
|
||||
while (i < n) {
|
||||
sum =sum+ v[i] * u[i];
|
||||
i=i+1;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
void mult1(float v[], float out[],int n) {
|
||||
int i = 0, j = 0;
|
||||
float sum = 0;
|
||||
|
||||
while (i < n) {
|
||||
while (j < n) {
|
||||
sum =sum+ v[j] / func(i,j);
|
||||
j=j+1;
|
||||
}
|
||||
out[i] = sum;
|
||||
i=i+1;
|
||||
}
|
||||
}
|
||||
|
||||
void mult2(float v[], float out[], int n) {
|
||||
int i = 0, j = 0;
|
||||
float sum = 0;
|
||||
|
||||
while (i < n) {
|
||||
while (j < n) {
|
||||
sum =sum+ v[j] / func(j,i);
|
||||
j=j+1;
|
||||
}
|
||||
out[i] = sum;
|
||||
i=i+1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void mult_combin(float v[], float out[], int n, float tmp[]) {
|
||||
mult1(v, tmp, n);
|
||||
mult2(tmp, out, n);
|
||||
}
|
||||
|
||||
float temp = 1;
|
||||
float my_sqrt(float input) {
|
||||
while (temp - input / temp > 1e-6 || temp - input / temp < -1e-6){
|
||||
temp = (temp+input/temp)/2;
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int n = 100000;
|
||||
if (n <= 0) {
|
||||
n = 2000;
|
||||
}
|
||||
starttime();
|
||||
float vectorA[100000], vectorB[100000], Vectortmp[100000];
|
||||
|
||||
int i;
|
||||
while(i < n) {
|
||||
vectorA[i] = 1;
|
||||
i=i+1;
|
||||
}
|
||||
i = 0;
|
||||
while(i < 1000) {
|
||||
mult_combin(vectorA, vectorB, n, Vectortmp);
|
||||
mult_combin(vectorB, vectorA, n, Vectortmp);
|
||||
i=i+1;
|
||||
}
|
||||
stoptime();
|
||||
float result = my_sqrt(Vectordot(vectorA,vectorB, n) / Vectordot(vectorB,vectorB,n));
|
||||
if(result - 1.000000 <= 1e-6 && result - 1.000000 >= -1e-6){
|
||||
putint(1);
|
||||
}else{
|
||||
putint(0);
|
||||
}
|
||||
putch(10);
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
3
|
||||
@ -0,0 +1,3 @@
|
||||
int main(){
|
||||
return 3;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
10
|
||||
@ -0,0 +1,8 @@
|
||||
//test domain of global var define and local define
|
||||
int a = 3;
|
||||
int b = 5;
|
||||
|
||||
int main(){
|
||||
int a = 5;
|
||||
return a + b;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
5
|
||||
@ -0,0 +1,8 @@
|
||||
//test local var define
|
||||
int main(){
|
||||
int a, b0, _c;
|
||||
a = 1;
|
||||
b0 = 2;
|
||||
_c = 3;
|
||||
return b0 + _c;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
0
|
||||
@ -0,0 +1,4 @@
|
||||
int a[10][10];
|
||||
int main(){
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
14
|
||||
@ -0,0 +1,9 @@
|
||||
//test array define
|
||||
int main(){
|
||||
int a[4][2] = {};
|
||||
int b[4][2] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
int c[4][2] = {{1, 2}, {3, 4}, {5, 6}, {7, 8}};
|
||||
int d[4][2] = {1, 2, {3}, {5}, 7 , 8};
|
||||
int e[4][2] = {{d[2][1], c[2][1]}, {3, 4}, {5, 6}, {7, 8}};
|
||||
return e[3][1] + e[0][0] + e[0][1] + a[2][0];
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
int main(){
|
||||
const int a[4][2] = {{1, 2}, {3, 4}, {}, 7};
|
||||
|
||||
int b[4][2] = {};
|
||||
int c[4][2] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
int d[3 + 1][2] = {1, 2, {3}, {5}, a[3][0], 8};
|
||||
int e[4][2][1] = {{d[2][1], {c[2][1]}}, {3, 4}, {5, 6}, {7, 8}};
|
||||
return e[3][1][0] + e[0][0][0] + e[0][1][0] + d[3][0];
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
5
|
||||
@ -0,0 +1,6 @@
|
||||
//test const gloal var define
|
||||
const int a = 10, b = 5;
|
||||
|
||||
int main(){
|
||||
return b;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
5
|
||||
@ -0,0 +1,5 @@
|
||||
//test const local var define
|
||||
int main(){
|
||||
const int a = 10, b = 5;
|
||||
return b;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
4
|
||||
@ -0,0 +1,5 @@
|
||||
const int a[5]={0,1,2,3,4};
|
||||
|
||||
int main(){
|
||||
return a[4];
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
4
|
||||
@ -0,0 +1,8 @@
|
||||
int defn(){
|
||||
return 4;
|
||||
}
|
||||
|
||||
int main(){
|
||||
int a=defn();
|
||||
return a;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
15
|
||||
@ -0,0 +1,5 @@
|
||||
//test addc
|
||||
const int a = 10;
|
||||
int main(){
|
||||
return a + 5;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
8
|
||||
@ -0,0 +1,6 @@
|
||||
//test subc
|
||||
int main(){
|
||||
int a;
|
||||
a = 10;
|
||||
return a - 2;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue