From: Matt Arsenault Date: Wed, 29 Jul 2020 13:48:26 +0000 (-0400) Subject: GlobalISel: Handle llvm.localescape X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=3e16e2152cd1fb3914d4da47d83d5e023dd3f2cb;p=platform%2Fupstream%2Fllvm.git GlobalISel: Handle llvm.localescape This one is pretty easy and shrinks the list of unhandled intrinsics. I'm not sure how relevant the insert point is. Using the insert position of EntryBuilder will place this after constants. SelectionDAG seems to end up emitting these after argument copies and before anything else, but I don't think it really matters. This also ends up emitting these in the opposite order from SelectionDAG, but I don't think that matters either. This also needs a fix to stop the later passes dropping this as a dead instruction. DeadMachineInstructionElim's version of isDead special cases LOCAL_ESCAPE for some reason, and I'm not sure why it's excluded from MachineInstr::isLabel (or why isDead doesn't check it). I also noticed DeadMachineInstructionElim never considers inline asm as dead, but GlobalISel will drop asm with no constraints. --- diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp index be669ec..ac867b4 100644 --- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp +++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -29,6 +29,7 @@ #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineMemOperand.h" +#include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineOperand.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/StackProtector.h" @@ -1658,6 +1659,33 @@ bool IRTranslator::translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID, .addUse(getOrCreateVReg(*CI.getArgOperand(1))); return true; } + case Intrinsic::localescape: { + MachineBasicBlock &EntryMBB = MF->front(); + StringRef EscapedName = GlobalValue::dropLLVMManglingEscape(MF->getName()); + + // Directly emit some LOCAL_ESCAPE machine instrs. Label assignment emission + // is the same on all targets. + for (unsigned Idx = 0, E = CI.getNumArgOperands(); Idx < E; ++Idx) { + Value *Arg = CI.getArgOperand(Idx)->stripPointerCasts(); + if (isa(Arg)) + continue; // Skip null pointers. They represent a hole in index space. + + int FI = getOrCreateFrameIndex(*cast(Arg)); + MCSymbol *FrameAllocSym = + MF->getMMI().getContext().getOrCreateFrameAllocSymbol(EscapedName, + Idx); + + // This should be inserted at the start of the entry block. + auto LocalEscape = + MIRBuilder.buildInstrNoInsert(TargetOpcode::LOCAL_ESCAPE) + .addSym(FrameAllocSym) + .addFrameIndex(FI); + + EntryMBB.insert(EntryMBB.begin(), LocalEscape); + } + + return true; + } #define INSTRUCTION(NAME, NARG, ROUND_MODE, INTRINSIC) \ case Intrinsic::INTRINSIC: #include "llvm/IR/ConstrainedOps.def" diff --git a/llvm/lib/CodeGen/GlobalISel/Utils.cpp b/llvm/lib/CodeGen/GlobalISel/Utils.cpp index 4a7513f..7fc738a 100644 --- a/llvm/lib/CodeGen/GlobalISel/Utils.cpp +++ b/llvm/lib/CodeGen/GlobalISel/Utils.cpp @@ -180,6 +180,14 @@ bool llvm::canReplaceReg(Register DstReg, Register SrcReg, bool llvm::isTriviallyDead(const MachineInstr &MI, const MachineRegisterInfo &MRI) { + // FIXME: This logical is mostly duplicated with + // DeadMachineInstructionElim::isDead. Why is LOCAL_ESCAPE not considered in + // MachineInstr::isLabel? + + // Don't delete frame allocation labels. + if (MI.getOpcode() == TargetOpcode::LOCAL_ESCAPE) + return false; + // If we can move an instruction, we can remove it. Otherwise, it has // a side-effect of some sort. bool SawStore = false; diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-localescape.ll b/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-localescape.ll new file mode 100644 index 0000000..60eaea4 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-localescape.ll @@ -0,0 +1,70 @@ +; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +; RUN: llc -global-isel -mtriple=arm64-windows -stop-after=irtranslator -o - %s | FileCheck %s + +define void @local_escape() { + ; CHECK-LABEL: name: local_escape + ; CHECK: bb.1 (%ir-block.0): + ; CHECK: LOCAL_ESCAPE , %stack.1.b + ; CHECK: LOCAL_ESCAPE , %stack.0.a + ; CHECK: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 42 + ; CHECK: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 13 + ; CHECK: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0.a + ; CHECK: [[FRAME_INDEX1:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.1.b + ; CHECK: G_STORE [[C]](s32), [[FRAME_INDEX]](p0) :: (store 4 into %ir.a) + ; CHECK: G_STORE [[C1]](s32), [[FRAME_INDEX1]](p0) :: (store 4 into %ir.b) + ; CHECK: RET_ReallyLR + %a = alloca i32 + %b = alloca i32, i32 2 + call void (...) @llvm.localescape(i32* %a, i32* %b) + store i32 42, i32* %a + store i32 13, i32* %b + ret void +} + +; Try some instructions before the localescape, and use a null +define void @local_escape_insert_point() { + ; CHECK-LABEL: name: local_escape_insert_point + ; CHECK: bb.1 (%ir-block.0): + ; CHECK: LOCAL_ESCAPE , %stack.1.b + ; CHECK: LOCAL_ESCAPE , %stack.0.a + ; CHECK: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 42 + ; CHECK: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 13 + ; CHECK: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0.a + ; CHECK: [[FRAME_INDEX1:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.1.b + ; CHECK: G_STORE [[C]](s32), [[FRAME_INDEX]](p0) :: (store 4 into %ir.a) + ; CHECK: G_STORE [[C1]](s32), [[FRAME_INDEX1]](p0) :: (store 4 into %ir.b) + ; CHECK: RET_ReallyLR + %a = alloca i32 + %b = alloca i32, i32 2 + store i32 42, i32* %a + store i32 13, i32* %b + call void (...) @llvm.localescape(i32* %a, i32* null, i32* %b) + ret void +} + +declare void @foo([128 x i32]*) + +; Check a cast of an alloca +define void @local_escape_strip_ptr_cast() { + ; CHECK-LABEL: name: local_escape_strip_ptr_cast + ; CHECK: bb.1 (%ir-block.0): + ; CHECK: LOCAL_ESCAPE , %stack.0.a + ; CHECK: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 42 + ; CHECK: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0.a + ; CHECK: G_STORE [[C]](s32), [[FRAME_INDEX]](p0) :: (store 4 into %ir.cast) + ; CHECK: ADJCALLSTACKDOWN 0, 0, implicit-def $sp, implicit $sp + ; CHECK: $x0 = COPY [[FRAME_INDEX]](p0) + ; CHECK: BL @foo, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit $x0 + ; CHECK: ADJCALLSTACKUP 0, 0, implicit-def $sp, implicit $sp + ; CHECK: RET_ReallyLR + %a = alloca [128 x i32] + %cast = bitcast [128 x i32]* %a to i32* + store i32 42, i32* %cast + call void (...) @llvm.localescape(i32* %cast, i32* null) + call void @foo([128 x i32]* %a) + ret void +} + +declare void @llvm.localescape(...) #0 + +attributes #0 = { nounwind } diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/labels-are-not-dead.mir b/llvm/test/CodeGen/AArch64/GlobalISel/labels-are-not-dead.mir new file mode 100644 index 0000000..ae7c7d3 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/GlobalISel/labels-are-not-dead.mir @@ -0,0 +1,34 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -march=aarch64 -run-pass=legalizer %s -o - | FileCheck %s + +# The LOCAL_ESCAPE instructions should not be deleted as dead. + +--- +name: no_erase_local_escape +tracksRegLiveness: true +stack: + - { id: 0, size: 4, alignment: 4 } + - { id: 1, size: 8, alignment: 4 } +body: | + bb.0: + ; CHECK-LABEL: name: no_erase_local_escape + ; CHECK: LOCAL_ESCAPE , %stack.0 + ; CHECK: LOCAL_ESCAPE , %stack.1 + ; CHECK: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 42 + ; CHECK: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 13 + ; CHECK: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0 + ; CHECK: [[FRAME_INDEX1:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.1 + ; CHECK: G_STORE [[C]](s32), [[FRAME_INDEX]](p0) :: (store 4) + ; CHECK: G_STORE [[C1]](s32), [[FRAME_INDEX1]](p0) :: (store 4) + ; CHECK: RET_ReallyLR + LOCAL_ESCAPE , %stack.0 + LOCAL_ESCAPE , %stack.1 + %2:_(s32) = G_CONSTANT i32 42 + %3:_(s32) = G_CONSTANT i32 13 + %0:_(p0) = G_FRAME_INDEX %stack.0 + %1:_(p0) = G_FRAME_INDEX %stack.1 + G_STORE %2(s32), %0(p0) :: (store 4) + G_STORE %3(s32), %1(p0) :: (store 4) + RET_ReallyLR + +...