This is an archive of the discontinued LLVM Phabricator instance.

Introduce new @llvm.getdynamicareaoffset.i{32, 64} intrinsic.
ClosedPublic

Authored by m.ostapenko on Nov 25 2015, 5:03 AM.

Details

Summary

As discussed in llvm-dev ML (https://groups.google.com/forum/m/#!topic/llvm-dev/42tNzaHISdk), we rely on @llvm.stackrestore intrinsic to get "bottom" parameter for asan_allocas_unpoison routine to perform stack unpoisoning for deallocated dynamic alloca into ASan runtime. For most targets this is fine, because SP to be restored is guaranteed to be higher than the highest poisoned byte for this alloca, but for PowerPC{64} the situation is different (see http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html#DYNAM-STACK). Here we cannot use SP as "bottom" parameter for asan_allocas_unpoison, because we can just miss unpoisoning of the highest part of right redzone for given alloca.

This patch introduces new @llvm.getdynamicareaoffset.i{32, 64} intrinsic that returns offset from native SP to end of dynamic stack area for given frame. For most targets that would be just 0, for others (e.g. PPC) it would be a compile time known nonzero constant. By adding this value to SP, we can make sure that we would have correct address to pass into __asan_allocas_unpoison as "bottom" and the whole right redzone would be unpoisoned.

Diff Detail

Repository
rL LLVM

Event Timeline

m.ostapenko retitled this revision from to Introduce new @llvm.getdynamicareaoffset.i{32, 64} intrinsic..
m.ostapenko updated this object.
m.ostapenko added a reviewer: hfinkel.
m.ostapenko set the repository for this revision to rL LLVM.
m.ostapenko added subscribers: foad, ygribov, llvm-commits.
hfinkel edited edge metadata.Nov 25 2015, 3:11 PM

You need to add documentation for the intrinsic into the LangRef.

include/llvm/CodeGen/ISDOpcodes.h
758 ↗(On Diff #41127)

offset is repeated twice here in a confusing way. We should define what we mean by "dynamic stack area" - is this one past the end of the last dynamic alloca?

759 ↗(On Diff #41127)

compile time -> compile-time

761 ↗(On Diff #41127)

What's the return type? Always the pointer type?

What happens if someone declares this with type i32 on a 64-bit system? We should not just randomly assert somewhere in this case; either handle it by doing an extend-or-truncate somewhere, or issue an error somewhere if the type does not match the pointer size type, and document the requirement in the LangRef.

lib/CodeGen/IntrinsicLowering.cpp
428 ↗(On Diff #41127)

This class is only used by the IR interpreter, as far as I can tell. While using 0 is probably not unreasonable, this comment does not explain why, and we should probably produce an error (as with returnaddress/frameaddress below).

lib/CodeGen/TargetLoweringBase.cpp
886 ↗(On Diff #41127)

We do support targets with i16 pointers (etc.) -- using a fixed list here is not necessary. Just put this inside the for (MVT VT : MVT::all_valuetypes()) loop that starts at the beginning of the function.

m.ostapenko added inline comments.Nov 26 2015, 2:37 AM
include/llvm/CodeGen/ISDOpcodes.h
758 ↗(On Diff #41127)

offset is repeated twice here in a confusing way.

Ugh, sorry.

We should define what we mean by "dynamic stack area" - is this one past the end of the last dynamic alloca?

Agreed.
Under "dynamic stack area" I mean the lowest address of local variable space after the last dynamic alloca. Frankly, I'm not sure "get dynamic stack area offset" is a good description for this intrinsic, any suggestions here are appreciated.

761 ↗(On Diff #41127)

Hm, I use llvm_anyint_ty in IR/Intrinsics.td, so I suspect this should be i32 for 32-bit targets and i64 for 64-bit ones. So, it seems that for most targets that would be pointer type, right?

What happens if someone declares this with type i32 on a 64-bit system? We should not just randomly assert somewhere in this case; either handle it by doing an extend-or-truncate somewhere, or issue an error somewhere if the type does not match the pointer size type, and document the requirement in the LangRef.

If I understand you correctly, you mean what happens if someone add new custom lowering routine for some target, right? If someone declares this intrinsic with a wrong type, he would get Expand action in Action = TLI.getOperationAction during node legalization in SelectionDAGLegalize::LegalizeOp. Issuing an error in such a case would be nice, thought.

lib/CodeGen/TargetLoweringBase.cpp
886 ↗(On Diff #41127)

Ok.

m.ostapenko added inline comments.Nov 26 2015, 5:24 AM
include/llvm/CodeGen/ISDOpcodes.h
761 ↗(On Diff #41127)

What happens if someone declares this with type i32 on a 64-bit system? We should not just randomly assert somewhere in this case; either handle it by doing an extend-or-truncate somewhere, or issue an error somewhere if the type does not match the pointer size type, and document the requirement in the LangRef.

If I understand you correctly, you mean what happens if someone add new custom lowering routine for some target, right? If someone declares this intrinsic with a wrong type, he would get Expand action in Action = TLI.getOperationAction during node legalization in SelectionDAGLegalize::LegalizeOp. Issuing an error in such a case would be nice, thought.

Ah, I see, perhaps you meant something like this (here we use @llvm.getdynamicareaoffset.i32() on PPC64):

; RUN: llc -mtriple=powerpc64-unknown-linux-gnu -mcpu=pwr7 < %s | FileCheck %s
target datalayout = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-f128:128:128-v128:128:128-n32:64"
target triple = "powerpc64-unknown-linux-gnu"

declare i32 @llvm.getdynamicareaoffset.i32()

declare i64 @bar(i32)

attributes #0 = { nounwind }

; Function Attrs: nounwind sanitize_address uwtable
define signext i64 @foo(i32 signext %N, i32 signext %M) #0 {
  %1 = alloca i64, align 32
  %getdynamicareaoffset1 = call i32 @llvm.getdynamicareaoffset.i32()
  %2 = call i64 @bar(i32 %getdynamicareaoffset1)
  ret i64 %2

; CHECK-DAG: li [[REG1:[0-9]+]], 112
; CHECK: blr

}

Sorry for being dumb here. I'll insert an assertion to corresponding handle into visitIntrinsicCall function.

foad added inline comments.Nov 26 2015, 5:37 AM
include/llvm/CodeGen/ISDOpcodes.h
758 ↗(On Diff #41127)

We should define what we mean by "dynamic stack area" - is this one past the end of the last dynamic alloca?

How about:

/// GET_DYNAMIC_AREA_OFFSET - get offset from native SP to the address
/// of the most recent dynamic alloca.
lib/Target/PowerPC/PPCISelLowering.cpp
5825 ↗(On Diff #41127)

"DYNAREAOFFSET"

m.ostapenko edited edge metadata.
m.ostapenko removed rL LLVM as the repository for this revision.

Updating the patch according to Hal's and Jay's nits.

hfinkel added inline comments.Nov 26 2015, 7:41 AM
docs/LangRef.rst
9357 ↗(On Diff #41249)

Please make sure you define what this means, both for stacks that grow down and also for stacks that grow up.

9357 ↗(On Diff #41249)

SP -> stack pointer

9358 ↗(On Diff #41249)

in the function stack -> on the caller's stack

9361 ↗(On Diff #41249)

This is useful, for example, for AddressSanitizer's stack-unpoisoning routines.

9367 ↗(On Diff #41249)

SP -> stack pointer

9368 ↗(On Diff #41249)

Remove "or gotten somehow else."

9370 ↗(On Diff #41249)

Remember to include the requirement that the return type match the address-space-0 pointer size.

Hal, thank you for your nits. Trying to improve new documentation.

m.ostapenko marked 17 inline comments as done.Nov 26 2015, 9:15 AM
hfinkel added inline comments.Nov 26 2015, 9:54 AM
docs/LangRef.rst
9373 ↗(On Diff #41262)
For targets where stack grows upwards, the situation is a bit more
complicated, because substracting this value from stack pointer would get the address
one past the end of the most-recent dynamic alloca.
9379 ↗(On Diff #41262)

The return value type

9380 ↗(On Diff #41262)

address-space-0 -> remove dashes (not needed because it is not a compound adjective as you have it here).

9383 ↗(On Diff #41262)

I'd remove this. You can add "Not supported on all targets" if you'd like, but given that zero is a reasonable default, I'm not sure how much value that adds.

Thanks again for the nits! Updating the patch.

hfinkel accepted this revision.Dec 1 2015, 1:50 AM
hfinkel edited edge metadata.

A few more wording/naming things, otherwise, LGTM.

docs/LangRef.rst
9350 ↗(On Diff #41282)

We're somewhat inconsistent about this, but we mostly separate words in intrinsic names with periods, and I think we should do that here as well.

llvm.get.dynamic.area.offset.*
9360 ↗(On Diff #41282)

Do you mean llvm.stacksave?

9373 ↗(On Diff #41282)

most-recent -> most recent

[I know, I'm correcting my suggestion from the previous review]

9377 ↗(On Diff #41282)

compile-time known -> compile-time-known

9380 ↗(On Diff #41282)

must match generic -> must match the target's generic

remove "for given target"

9381 ↗(On Diff #41282)

Remove ", otherwise LLVM would issue an error on the lowering stage" -- the LangRef does not define how LLVM responds to invalid input.

This revision is now accepted and ready to land.Dec 1 2015, 1:50 AM
m.ostapenko updated this revision to Diff 41479.Dec 1 2015, 3:25 AM
m.ostapenko edited edge metadata.

Thanks! Here the patch to be committed.

This revision was automatically updated to reflect the committed changes.