#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"
.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<ConstantPointerNull>(Arg))
+ continue; // Skip null pointers. They represent a hole in index space.
+
+ int FI = getOrCreateFrameIndex(*cast<AllocaInst>(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"
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;
--- /dev/null
+; 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 <mcsymbol .Llocal_escape$frame_escape_1>, %stack.1.b
+ ; CHECK: LOCAL_ESCAPE <mcsymbol .Llocal_escape$frame_escape_0>, %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 <mcsymbol .Llocal_escape_insert_point$frame_escape_2>, %stack.1.b
+ ; CHECK: LOCAL_ESCAPE <mcsymbol .Llocal_escape_insert_point$frame_escape_0>, %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 <mcsymbol .Llocal_escape_strip_ptr_cast$frame_escape_0>, %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 }
--- /dev/null
+# 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 <mcsymbol .Llocal_escape$frame_escape_0>, %stack.0
+ ; CHECK: LOCAL_ESCAPE <mcsymbol .Llocal_escape$frame_escape_1>, %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 <mcsymbol .Llocal_escape$frame_escape_0>, %stack.0
+ LOCAL_ESCAPE <mcsymbol .Llocal_escape$frame_escape_1>, %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
+
+...