diff options
| author | Daniel Sanders <daniel_l_sanders@apple.com> | 2018-10-03 02:21:30 +0000 |
|---|---|---|
| committer | Daniel Sanders <daniel_l_sanders@apple.com> | 2018-10-03 02:21:30 +0000 |
| commit | 34eac35a6096163bce8a889f0c9a696cedfca08a (patch) | |
| tree | 9acddc14549bdb84cc89d5a144b16be54d5a3516 | |
| parent | c973ad1878f335fbb90fd1ac421fa6309746fe53 (diff) | |
| download | bcm5719-llvm-34eac35a6096163bce8a889f0c9a696cedfca08a.tar.gz bcm5719-llvm-34eac35a6096163bce8a889f0c9a696cedfca08a.zip | |
Add the missing new files from r343654
llvm-svn: 343655
| -rw-r--r-- | llvm/lib/Target/AArch64/AArch64PreLegalizerCombiner.cpp | 108 | ||||
| -rw-r--r-- | llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-extending-loads.mir | 450 |
2 files changed, 558 insertions, 0 deletions
diff --git a/llvm/lib/Target/AArch64/AArch64PreLegalizerCombiner.cpp b/llvm/lib/Target/AArch64/AArch64PreLegalizerCombiner.cpp new file mode 100644 index 00000000000..32487b9ccc3 --- /dev/null +++ b/llvm/lib/Target/AArch64/AArch64PreLegalizerCombiner.cpp @@ -0,0 +1,108 @@ +//=== lib/CodeGen/GlobalISel/AArch64PreLegalizerCombiner.cpp --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass does combining of machine instructions at the generic MI level, +// before the legalizer. +// +//===----------------------------------------------------------------------===// + +#include "AArch64TargetMachine.h" +#include "llvm/CodeGen/GlobalISel/Combiner.h" +#include "llvm/CodeGen/GlobalISel/CombinerHelper.h" +#include "llvm/CodeGen/GlobalISel/CombinerInfo.h" +#include "llvm/CodeGen/GlobalISel/MIPatternMatch.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/TargetPassConfig.h" +#include "llvm/Support/Debug.h" + +#define DEBUG_TYPE "aarch64-prelegalizer-combiner" + +using namespace llvm; +using namespace MIPatternMatch; + +namespace { +class AArch64PreLegalizerCombinerInfo : public CombinerInfo { +public: + AArch64PreLegalizerCombinerInfo() + : CombinerInfo(/*AllowIllegalOps*/ true, /*ShouldLegalizeIllegal*/ false, + /*LegalizerInfo*/ nullptr) {} + virtual bool combine(CombinerChangeObserver &Observer, MachineInstr &MI, + MachineIRBuilder &B) const override; +}; + +bool AArch64PreLegalizerCombinerInfo::combine(CombinerChangeObserver &Observer, + MachineInstr &MI, + MachineIRBuilder &B) const { + CombinerHelper Helper(Observer, B); + + switch (MI.getOpcode()) { + default: + return false; + case TargetOpcode::G_LOAD: + case TargetOpcode::G_SEXTLOAD: + case TargetOpcode::G_ZEXTLOAD: + return Helper.tryCombineExtendingLoads(MI); + } + + return false; +} + +// Pass boilerplate +// ================ + +class AArch64PreLegalizerCombiner : public MachineFunctionPass { +public: + static char ID; + + AArch64PreLegalizerCombiner(); + + StringRef getPassName() const override { return "AArch64PreLegalizerCombiner"; } + + bool runOnMachineFunction(MachineFunction &MF) override; + + void getAnalysisUsage(AnalysisUsage &AU) const override; +}; +} + +void AArch64PreLegalizerCombiner::getAnalysisUsage(AnalysisUsage &AU) const { + AU.addRequired<TargetPassConfig>(); + AU.setPreservesCFG(); + getSelectionDAGFallbackAnalysisUsage(AU); + MachineFunctionPass::getAnalysisUsage(AU); +} + +AArch64PreLegalizerCombiner::AArch64PreLegalizerCombiner() : MachineFunctionPass(ID) { + initializeAArch64PreLegalizerCombinerPass(*PassRegistry::getPassRegistry()); +} + +bool AArch64PreLegalizerCombiner::runOnMachineFunction(MachineFunction &MF) { + if (MF.getProperties().hasProperty( + MachineFunctionProperties::Property::FailedISel)) + return false; + auto *TPC = &getAnalysis<TargetPassConfig>(); + AArch64PreLegalizerCombinerInfo PCInfo; + Combiner C(PCInfo, TPC); + return C.combineMachineInstrs(MF); +} + +char AArch64PreLegalizerCombiner::ID = 0; +INITIALIZE_PASS_BEGIN(AArch64PreLegalizerCombiner, DEBUG_TYPE, + "Combine AArch64 machine instrs before legalization", + false, false) +INITIALIZE_PASS_DEPENDENCY(TargetPassConfig) +INITIALIZE_PASS_END(AArch64PreLegalizerCombiner, DEBUG_TYPE, + "Combine AArch64 machine instrs before legalization", false, + false) + + +namespace llvm { +FunctionPass *createAArch64PreLegalizeCombiner() { + return new AArch64PreLegalizerCombiner(); +} +} // end namespace llvm diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-extending-loads.mir b/llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-extending-loads.mir new file mode 100644 index 00000000000..5f1d9142ea8 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-extending-loads.mir @@ -0,0 +1,450 @@ +# RUN: llc -O0 -run-pass=aarch64-prelegalizer-combiner -global-isel %s -o - | FileCheck %s + +--- | + target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" + target triple = "aarch64--" + define void @test_anyext(i8* %addr) { + entry: + ret void + } + define void @test_anyext_with_copy(i8* %addr) { + entry: + ret void + } + define void @test_signext(i8* %addr) { + entry: + ret void + } + define void @test_zeroext(i8* %addr) { + entry: + ret void + } + define void @test_2anyext(i8* %addr) { + entry: + ret void + } + define void @test_1anyext_1signext(i8* %addr) { + entry: + ret void + } + define void @test_1xor_1signext(i8* %addr) { + entry: + ret void + } + define void @test_1anyext_1zeroext(i8* %addr) { + entry: + ret void + } + define void @test_1signext_1zeroext(i8* %addr) { + entry: + ret void + } + define void @test_1anyext64_1signext32(i8* %addr) { + entry: + ret void + } + define void @test_1anyext32_1signext64(i8* %addr) { + entry: + ret void + } + define void @test_2anyext32_1signext64(i8* %addr) { + entry: + ret void + } + define void @test_multiblock_anyext(i8* %addr) { + entry: + ret void + } + define void @test_multiblock_signext(i8* %addr) { + entry: + ret void + } + define void @test_multiblock_zeroext(i8* %addr) { + entry: + ret void + } + define void @test_multiblock_2anyext(i8* %addr) { + entry: + ret void + } + define void @test_multiblock_1anyext64_1signext32(i8* %addr) { + entry: + ret void + } + define void @test_multiblock_1anyext32_1signext64(i8* %addr) { + entry: + ret void + } + define void @test_multiblock_2anyext32_1signext64(i8* %addr) { + entry: + ret void + } +... + +--- +name: test_anyext +body: | + bb.0.entry: + liveins: $x0 + ; CHECK-LABEL: name: test_anyext + ; CHECK: [[T0:%[0-9]+]]:_(p0) = COPY $x0 + ; CHECK: [[T1:%[0-9]+]]:_(s32) = G_LOAD [[T0]](p0) :: (load 1 from %ir.addr) + ; CHECK: $w0 = COPY [[T1]](s32) + %0:_(p0) = COPY $x0 + %1:_(s8) = G_LOAD %0 :: (load 1 from %ir.addr) + %2:_(s32) = G_ANYEXT %1 + $w0 = COPY %2 +... + +--- +name: test_anyext_with_copy +body: | + bb.0.entry: + liveins: $x0 + ; CHECK-LABEL: name: test_anyext + ; CHECK: [[T0:%[0-9]+]]:_(p0) = COPY $x0 + ; CHECK: [[T1:%[0-9]+]]:_(s32) = G_LOAD [[T0]](p0) :: (load 1 from %ir.addr) + ; CHECK: $w0 = COPY [[T1]](s32) + %0:_(p0) = COPY $x0 + %1:_(s8) = G_LOAD %0 :: (load 1 from %ir.addr) + %2:_(s8) = COPY %1 + %3:_(s32) = G_ANYEXT %1 + $w0 = COPY %3 +... + +--- +name: test_signext +body: | + bb.0.entry: + liveins: $x0 + ; CHECK-LABEL: name: test_signext + ; CHECK: [[T0:%[0-9]+]]:_(p0) = COPY $x0 + ; CHECK: [[T1:%[0-9]+]]:_(s32) = G_SEXTLOAD [[T0]](p0) :: (load 1 from %ir.addr) + ; CHECK: $w0 = COPY [[T1]](s32) + %0:_(p0) = COPY $x0 + %1:_(s8) = G_LOAD %0 :: (load 1 from %ir.addr) + %2:_(s32) = G_SEXT %1 + $w0 = COPY %2 +... + +--- +name: test_zeroext +body: | + bb.0.entry: + liveins: $x0 + ; CHECK-LABEL: name: test_zeroext + ; CHECK: [[T0:%[0-9]+]]:_(p0) = COPY $x0 + ; CHECK: [[T1:%[0-9]+]]:_(s32) = G_ZEXTLOAD [[T0]](p0) :: (load 1 from %ir.addr) + ; CHECK: $w0 = COPY [[T1]](s32) + %0:_(p0) = COPY $x0 + %1:_(s8) = G_LOAD %0 :: (load 1 from %ir.addr) + %2:_(s32) = G_ZEXT %1 + $w0 = COPY %2 +... + +--- +name: test_2anyext +body: | + bb.0.entry: + liveins: $x0 + ; CHECK-LABEL: name: test_2anyext + ; CHECK: [[T0:%[0-9]+]]:_(p0) = COPY $x0 + ; CHECK: [[T1:%[0-9]+]]:_(s32) = G_LOAD [[T0]](p0) :: (load 1 from %ir.addr) + ; CHECK: $w0 = COPY [[T1]](s32) + ; CHECK: $w1 = COPY [[T1]](s32) + %0:_(p0) = COPY $x0 + %1:_(s8) = G_LOAD %0 :: (load 1 from %ir.addr) + %2:_(s32) = G_ANYEXT %1 + %3:_(s32) = G_ANYEXT %1 + $w0 = COPY %2 + $w1 = COPY %3 +... + +--- +name: test_1anyext_1signext +body: | + bb.0.entry: + liveins: $x0 + ; CHECK-LABEL: name: test_1anyext_1signext + ; CHECK: [[T0:%[0-9]+]]:_(p0) = COPY $x0 + ; CHECK: [[T1:%[0-9]+]]:_(s32) = G_SEXTLOAD [[T0]](p0) :: (load 1 from %ir.addr) + ; CHECK: $w0 = COPY [[T1]](s32) + ; CHECK: $w1 = COPY [[T1]](s32) + %0:_(p0) = COPY $x0 + %1:_(s8) = G_LOAD %0 :: (load 1 from %ir.addr) + %2:_(s32) = G_ANYEXT %1 + %3:_(s32) = G_SEXT %1 + $w0 = COPY %2 + $w1 = COPY %3 +... + +--- +name: test_1xor_1signext +body: | + bb.0.entry: + liveins: $x0 + ; CHECK-LABEL: name: test_1xor_1signext + ; CHECK: [[T0:%[0-9]+]]:_(p0) = COPY $x0 + ; CHECK: [[T1:%[0-9]+]]:_(s32) = G_SEXTLOAD [[T0]](p0) :: (load 1 from %ir.addr) + ; CHECK: [[T2:%[0-9]+]]:_(s8) = G_TRUNC [[T1]] + ; CHECK: [[T3:%[0-9]+]]:_(s8) = G_XOR [[T2]], {{%[0-9]+}} + ; CHECK: [[T4:%[0-9]+]]:_(s32) = G_ANYEXT [[T3]] + ; CHECK: $w0 = COPY [[T4]](s32) + ; CHECK: $w1 = COPY [[T1]](s32) + %0:_(p0) = COPY $x0 + %1:_(s8) = G_LOAD %0 :: (load 1 from %ir.addr) + %2:_(s8) = G_CONSTANT i32 -1 + %3:_(s8) = G_XOR %1, %2 + %5:_(s32) = G_ANYEXT %3 + %6:_(s32) = G_SEXT %1 + $w0 = COPY %5 + $w1 = COPY %6 +... + +--- +name: test_1anyext_1zeroext +body: | + bb.0.entry: + liveins: $x0 + ; CHECK-LABEL: name: test_1anyext_1zeroext + ; CHECK: [[T0:%[0-9]+]]:_(p0) = COPY $x0 + ; CHECK: [[T1:%[0-9]+]]:_(s32) = G_ZEXTLOAD [[T0]](p0) :: (load 1 from %ir.addr) + ; CHECK: $w0 = COPY [[T1]](s32) + ; CHECK: $w1 = COPY [[T1]](s32) + %0:_(p0) = COPY $x0 + %1:_(s8) = G_LOAD %0 :: (load 1 from %ir.addr) + %2:_(s32) = G_ANYEXT %1 + %3:_(s32) = G_ZEXT %1 + $w0 = COPY %2 + $w1 = COPY %3 +... + +--- +name: test_1signext_1zeroext +body: | + bb.0.entry: + liveins: $x0 + ; CHECK-LABEL: name: test_1signext_1zeroext + ; CHECK: [[T0:%[0-9]+]]:_(p0) = COPY $x0 + ; CHECK: [[T1:%[0-9]+]]:_(s32) = G_SEXTLOAD [[T0]](p0) :: (load 1 from %ir.addr) + ; CHECK: [[T2:%[0-9]+]]:_(s8) = G_TRUNC [[T1]] + ; CHECK: [[T3:%[0-9]+]]:_(s32) = G_ZEXT [[T2]] + ; CHECK: $w0 = COPY [[T3]](s32) + ; CHECK: $w1 = COPY [[T1]](s32) + %0:_(p0) = COPY $x0 + %1:_(s8) = G_LOAD %0 :: (load 1 from %ir.addr) + %2:_(s32) = G_ZEXT %1 + %3:_(s32) = G_SEXT %1 + $w0 = COPY %2 + $w1 = COPY %3 +... + +--- +name: test_1anyext64_1signext32 +body: | + bb.0.entry: + liveins: $x0 + ; CHECK-LABEL: name: test_1anyext64_1signext32 + ; CHECK: [[T0:%[0-9]+]]:_(p0) = COPY $x0 + ; CHECK: [[T1:%[0-9]+]]:_(s32) = G_SEXTLOAD [[T0]](p0) :: (load 1 from %ir.addr) + ; CHECK: [[T2:%[0-9]+]]:_(s64) = G_ANYEXT [[T1]] + ; CHECK: $x0 = COPY [[T2]](s64) + ; CHECK: $w1 = COPY [[T1]](s32) + %0:_(p0) = COPY $x0 + %1:_(s8) = G_LOAD %0 :: (load 1 from %ir.addr) + %2:_(s64) = G_ANYEXT %1 + %3:_(s32) = G_SEXT %1 + $x0 = COPY %2 + $w1 = COPY %3 +... + +--- +name: test_1anyext32_1signext64 +body: | + bb.0.entry: + liveins: $x0 + ; CHECK-LABEL: name: test_1anyext32_1signext64 + ; CHECK: [[T0:%[0-9]+]]:_(p0) = COPY $x0 + ; CHECK: [[T1:%[0-9]+]]:_(s64) = G_SEXTLOAD [[T0]](p0) :: (load 1 from %ir.addr) + ; CHECK: [[T2:%[0-9]+]]:_(s8) = G_TRUNC [[T1]] + ; CHECK: [[T3:%[0-9]+]]:_(s32) = G_ANYEXT [[T2]] + ; CHECK: $w0 = COPY [[T3]](s32) + ; CHECK: $x1 = COPY [[T1]](s64) + %0:_(p0) = COPY $x0 + %1:_(s8) = G_LOAD %0 :: (load 1 from %ir.addr) + %2:_(s32) = G_ANYEXT %1 + %3:_(s64) = G_SEXT %1 + $w0 = COPY %2 + $x1 = COPY %3 +... + +--- +name: test_2anyext32_1signext64 +body: | + bb.0.entry: + liveins: $x0 + ; CHECK-LABEL: name: test_2anyext32_1signext64 + ; CHECK: [[T0:%[0-9]+]]:_(p0) = COPY $x0 + ; CHECK: [[T1:%[0-9]+]]:_(s64) = G_SEXTLOAD [[T0]](p0) :: (load 1 from %ir.addr) + ; CHECK: [[T2:%[0-9]+]]:_(s8) = G_TRUNC [[T1]] + ; CHECK: [[T3:%[0-9]+]]:_(s32) = G_ANYEXT [[T2]] + ; CHECK: [[T4:%[0-9]+]]:_(s8) = G_TRUNC [[T1]] + ; CHECK: [[T5:%[0-9]+]]:_(s32) = G_ANYEXT [[T4]] + ; CHECK: $w0 = COPY [[T3]](s32) + ; CHECK: $x1 = COPY [[T1]](s64) + ; CHECK: $w2 = COPY [[T5]](s32) + %0:_(p0) = COPY $x0 + %1:_(s8) = G_LOAD %0 :: (load 1 from %ir.addr) + %2:_(s32) = G_ANYEXT %1 + %3:_(s64) = G_SEXT %1 + %4:_(s32) = G_ANYEXT %1 + $w0 = COPY %2 + $x1 = COPY %3 + $w2 = COPY %4 +... + +--- +name: test_multiblock_anyext +body: | + bb.0.entry: + liveins: $x0 + ; CHECK-LABEL: name: test_multiblock_anyext + ; CHECK: [[T0:%[0-9]+]]:_(p0) = COPY $x0 + ; CHECK: [[T1:%[0-9]+]]:_(s32) = G_LOAD [[T0]](p0) :: (load 1 from %ir.addr) + ; CHECK: G_BR %bb.1 + ; CHECK: $w0 = COPY [[T1]](s32) + %0:_(p0) = COPY $x0 + %1:_(s8) = G_LOAD %0 :: (load 1 from %ir.addr) + G_BR %bb.1 + bb.1: + %2:_(s32) = G_ANYEXT %1 + $w0 = COPY %2 +... + +--- +name: test_multiblock_signext +body: | + bb.0.entry: + liveins: $x0 + ; CHECK-LABEL: name: test_multiblock_signext + ; CHECK: [[T0:%[0-9]+]]:_(p0) = COPY $x0 + ; CHECK: [[T1:%[0-9]+]]:_(s32) = G_SEXTLOAD [[T0]](p0) :: (load 1 from %ir.addr) + ; CHECK: $w0 = COPY [[T1]](s32) + %0:_(p0) = COPY $x0 + %1:_(s8) = G_LOAD %0 :: (load 1 from %ir.addr) + G_BR %bb.1 + bb.1: + %2:_(s32) = G_SEXT %1 + $w0 = COPY %2 +... + +--- +name: test_multiblock_zeroext +body: | + bb.0.entry: + liveins: $x0 + ; CHECK-LABEL: name: test_multiblock_zeroext + ; CHECK: [[T0:%[0-9]+]]:_(p0) = COPY $x0 + ; CHECK: [[T1:%[0-9]+]]:_(s32) = G_ZEXTLOAD [[T0]](p0) :: (load 1 from %ir.addr) + ; CHECK: $w0 = COPY [[T1]](s32) + %0:_(p0) = COPY $x0 + %1:_(s8) = G_LOAD %0 :: (load 1 from %ir.addr) + G_BR %bb.1 + bb.1: + %2:_(s32) = G_ZEXT %1 + $w0 = COPY %2 +... + +--- +name: test_multiblock_2anyext +body: | + bb.0.entry: + liveins: $x0 + ; CHECK-LABEL: name: test_multiblock + ; CHECK: [[T0:%[0-9]+]]:_(p0) = COPY $x0 + ; CHECK: [[T1:%[0-9]+]]:_(s32) = G_LOAD [[T0]](p0) :: (load 1 from %ir.addr) + ; CHECK: $w0 = COPY [[T1]](s32) + ; CHECK: $w1 = COPY [[T1]](s32) + %0:_(p0) = COPY $x0 + %1:_(s8) = G_LOAD %0 :: (load 1 from %ir.addr) + %2:_(s32) = G_ANYEXT %1 + G_BR %bb.1 + bb.1: + %3:_(s32) = G_ANYEXT %1 + $w0 = COPY %2 + $w1 = COPY %3 +... + +--- +name: test_multiblock_1anyext64_1signext32 +body: | + bb.0.entry: + liveins: $x0 + ; CHECK-LABEL: name: test_multiblock_1anyext64_1signext32 + ; CHECK: [[T0:%[0-9]+]]:_(p0) = COPY $x0 + ; CHECK: [[T1:%[0-9]+]]:_(s32) = G_SEXTLOAD [[T0]](p0) :: (load 1 from %ir.addr) + ; CHECK: G_BR %bb.1 + ; CHECK: [[T2:%[0-9]+]]:_(s64) = G_ANYEXT [[T1]] + ; CHECK: $x0 = COPY [[T2]](s64) + ; CHECK: $w1 = COPY [[T1]](s32) + %0:_(p0) = COPY $x0 + %1:_(s8) = G_LOAD %0 :: (load 1 from %ir.addr) + G_BR %bb.1 + bb.1: + %2:_(s64) = G_ANYEXT %1 + %3:_(s32) = G_SEXT %1 + $x0 = COPY %2 + $w1 = COPY %3 +... + +--- +name: test_multiblock_1anyext32_1signext64 +body: | + bb.0.entry: + liveins: $x0 + ; CHECK-LABEL: name: test_multiblock_1anyext32_1signext64 + ; CHECK: [[T0:%[0-9]+]]:_(p0) = COPY $x0 + ; CHECK: [[T1:%[0-9]+]]:_(s64) = G_SEXTLOAD [[T0]](p0) :: (load 1 from %ir.addr) + ; CHECK: G_BR %bb.1 + ; CHECK: [[T2:%[0-9]+]]:_(s8) = G_TRUNC [[T1]] + ; CHECK: [[T3:%[0-9]+]]:_(s32) = G_ANYEXT [[T2]] + ; CHECK: $w0 = COPY [[T3]](s32) + ; CHECK: $x1 = COPY [[T1]](s64) + %0:_(p0) = COPY $x0 + %1:_(s8) = G_LOAD %0 :: (load 1 from %ir.addr) + G_BR %bb.1 + bb.1: + %2:_(s32) = G_ANYEXT %1 + %3:_(s64) = G_SEXT %1 + $w0 = COPY %2 + $x1 = COPY %3 +... + +--- +name: test_multiblock_2anyext32_1signext64 +body: | + bb.0.entry: + liveins: $x0 + ; CHECK-LABEL: name: test_multiblock_2anyext32_1signext64 + ; CHECK: [[T0:%[0-9]+]]:_(p0) = COPY $x0 + ; CHECK: [[T1:%[0-9]+]]:_(s64) = G_SEXTLOAD [[T0]](p0) :: (load 1 from %ir.addr) + ; CHECK: [[T2:%[0-9]+]]:_(s8) = G_TRUNC [[T1]] + ; CHECK: [[T3:%[0-9]+]]:_(s32) = G_ANYEXT [[T2]] + ; CHECK: G_BR %bb.1 + ; CHECK: [[T4:%[0-9]+]]:_(s8) = G_TRUNC [[T1]] + ; CHECK: [[T5:%[0-9]+]]:_(s32) = G_ANYEXT [[T4]] + ; CHECK: $w0 = COPY [[T5]](s32) + ; CHECK: $x1 = COPY [[T1]](s64) + ; CHECK: $w2 = COPY [[T3]](s32) + %0:_(p0) = COPY $x0 + %1:_(s8) = G_LOAD %0 :: (load 1 from %ir.addr) + %4:_(s32) = G_ANYEXT %1 + G_BR %bb.1 + bb.1: + %2:_(s32) = G_ANYEXT %1 + %3:_(s64) = G_SEXT %1 + $w0 = COPY %2 + $x1 = COPY %3 + $w2 = COPY %4 +... + |

