Index: llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp =================================================================== --- llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp +++ 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" @@ -1672,6 +1673,33 @@ .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" Index: llvm/lib/CodeGen/GlobalISel/Utils.cpp =================================================================== --- llvm/lib/CodeGen/GlobalISel/Utils.cpp +++ llvm/lib/CodeGen/GlobalISel/Utils.cpp @@ -180,6 +180,14 @@ 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; Index: llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-localescape.ll =================================================================== --- /dev/null +++ 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 } Index: llvm/test/CodeGen/AArch64/GlobalISel/labels-are-not-dead.mir =================================================================== --- /dev/null +++ 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 + +...