This is an archive of the discontinued LLVM Phabricator instance.

[Verifier] Verify parameter alignment.
ClosedPublic

Authored by LuoYuanke on Mar 17 2022, 3:24 AM.

Details

Summary

In DAGISel, the parameter alignment only have 4 bits to hold the value.
The encode(alignment) would need extra 1 bit, so the max aligment that
ISel can support is 2^14. This patch verify the parameter, return value
and align attribute for parameter.

Diff Detail

Event Timeline

LuoYuanke created this revision.Mar 17 2022, 3:24 AM
Herald added a project: Restricted Project. · View Herald TranscriptMar 17 2022, 3:24 AM
Herald added a subscriber: hiraditya. · View Herald Transcript
LuoYuanke requested review of this revision.Mar 17 2022, 3:24 AM
Herald added a project: Restricted Project. · View Herald TranscriptMar 17 2022, 3:24 AM
LuoYuanke added a subscriber: skan.Mar 17 2022, 5:46 AM
skan added inline comments.Mar 17 2022, 8:51 PM
llvm/lib/IR/Verifier.cpp
1749

A question: why is the max alignment is not 1<<15 if we have 4 bits?

3159

This is a little weird. We hard-code the max number by the width of a bit field...

skan added a comment.Mar 17 2022, 8:53 PM

Is it possible that we define a common max alignment across all layers?

pengfei accepted this revision.Mar 17 2022, 11:12 PM

Is it possible that we define a common max alignment across all layers?

I think arbitrary/maximum alignment doesn't make sense in reality and usually implies something wrong. So adding a verifier seems a good choice. LGTM but wait one or two days for other reviewers.

This revision is now accepted and ready to land.Mar 17 2022, 11:12 PM
skan added inline comments.Mar 17 2022, 11:32 PM
llvm/lib/IR/Verifier.cpp
3156

At least we need to add comments at ArgFlagsTy::MemAlign to say that we verify the width of bit field in Verify.cpp.

Is it possible that we define a common max alignment across all layers?

After digging more in the LLVM code, I find there is MaximumAlignment (1 << 32) in Value.h (https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/IR/Value.h#L793) and constant null pointer would be set the MaximumAlignment at https://github.com/llvm/llvm-project/blob/main/llvm/lib/IR/Value.cpp#L977. Below test case would fail with my patch which constrain parameter alignment. To fix the max size conflict between MaximumAlignment and ArgFlagsTy.MemAlign maybe just use unsigned type for MemAlign instead of bitfield? But it seems there is assert to monitor ArgFlagsTy size at https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/CodeGen/TargetCallingConv.h#L69.

So in summary, for now I have no idea how to fix it. Maybe leave the test case of my patch just crash during the lowering and remind middle-end generate the right vector size or alignment attribute. @craig.topper, @RKSimon, @pengfei any ideas?

; RUN: opt -passes=instcombine -S < %s | FileCheck %s

define i32 @PR48810() {
; CHECK-LABEL: @PR48810(
; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 undef, i8* align 4294967296 null, i64 undef, i1 false)
; CHECK-NEXT:    ret i32 undef
;
  %r = call dereferenceable(1) i8* @mempcpy(i8* undef, i8* null, i64 undef)
  ret i32 undef
}

declare i8* @mempcpy(i8*, i8* nocapture readonly, i64)

Can we check if the pointer has byval/byref attribute? I think the MemAlign should only be meaningful for them. And if we simply passing a pointer with OrigAlign, it's safe to truncate to the maximum of MemAlign in backend.

Further more, byval/byref together with align attribute are all ABI related. It does make sense to have different alignment with a pure pointer used inside function only. Here's comment from LangRef:

The byval attribute also supports specifying an alignment with the align attribute. It indicates the alignment of the stack slot to form and the known alignment of the pointer specified to the call site. If the alignment is not specified, then the code generator makes a target-specific assumption.
skan added a reviewer: skan.Mar 18 2022, 11:01 PM

Is it possible that we define a common max alignment across all layers?

After digging more in the LLVM code, I find there is MaximumAlignment (1 << 32) in Value.h (https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/IR/Value.h#L793) and constant null pointer would be set the MaximumAlignment at https://github.com/llvm/llvm-project/blob/main/llvm/lib/IR/Value.cpp#L977. Below test case would fail with my patch which constrain parameter alignment. To fix the max size conflict between MaximumAlignment and ArgFlagsTy.MemAlign maybe just use unsigned type for MemAlign instead of bitfield? But it seems there is assert to monitor ArgFlagsTy size at https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/CodeGen/TargetCallingConv.h#L69.

So in summary, for now I have no idea how to fix it. Maybe leave the test case of my patch just crash during the lowering and remind middle-end generate the right vector size or alignment attribute. @craig.topper, @RKSimon, @pengfei any ideas?

; RUN: opt -passes=instcombine -S < %s | FileCheck %s

define i32 @PR48810() {
; CHECK-LABEL: @PR48810(
; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 undef, i8* align 4294967296 null, i64 undef, i1 false)
; CHECK-NEXT:    ret i32 undef
;
  %r = call dereferenceable(1) i8* @mempcpy(i8* undef, i8* null, i64 undef)
  ret i32 undef
}

declare i8* @mempcpy(i8*, i8* nocapture readonly, i64)

Could we add the max alignment information to Triple?

LuoYuanke updated this revision to Diff 416897.Mar 21 2022, 4:57 AM
  1. Remove the alignment attribute check. I plan to do it in another patch.
  2. Rebase.
LuoYuanke updated this revision to Diff 416903.Mar 21 2022, 5:21 AM

Address Shengchen's comments.

Can we check if the pointer has byval/byref attribute? I think the MemAlign should only be meaningful for them. And if we simply passing a pointer with OrigAlign, it's safe to truncate to the maximum of MemAlign in backend.

LGTM, thanks Phoebe. I create anther patch at https://reviews.llvm.org/D122130.

pengfei added inline comments.Mar 21 2022, 6:04 AM
llvm/lib/IR/Verifier.cpp
3155–3163

The variables are only used in Assert, should add #ifndef NDEBUG to them? Surprisingly I didn't find an example in this file.

llvm/test/Verifier/param-ret-align.ll
2

Can we merge them to one file?

LuoYuanke added inline comments.Mar 21 2022, 6:17 AM
llvm/lib/IR/Verifier.cpp
3155–3163

The Assert is defined as below. Let me check if it will fail in release build.

#define Assert(C, ...) \
  do { if (!(C)) { CheckFailed(__VA_ARGS__); return; } } while (false)
llvm/test/Verifier/param-ret-align.ll
2

Probably not. llvm-as would exit on the first failure.

skan added inline comments.Mar 21 2022, 6:26 PM
llvm/test/Verifier/param-ret-align.ll
2

Then? We could check more than one failure in a LIT test.

skan added inline comments.Mar 21 2022, 6:34 PM
llvm/lib/IR/Verifier.cpp
3155–3163

This Assert is different from assert. It is enabled no matter NDEBUG is turned on or off

Update comments.

pengfei accepted this revision.Mar 21 2022, 11:14 PM

Still fine to me.

llvm/test/Verifier/param-ret-align.ll
2

I understand it is the second function will never be handled once the first failed. With a rough search, I didn't find an example to handle more than one fucntions.

pengfei added inline comments.Mar 21 2022, 11:17 PM
llvm/lib/IR/Verifier.cpp
3155–3163

Good to know, thanks!

skan added inline comments.Mar 21 2022, 11:17 PM
llvm/test/Verifier/param-ret-align.ll
2

Oh, I understand what yuanke means now

Rebase and have constant for parameter max alignment.

skan accepted this revision.Mar 21 2022, 11:20 PM

LGTM now.

nikic added a subscriber: nikic.Mar 22 2022, 6:03 AM

Just to throw it out there, we should be able to support a larger alignment in ArgFlagsTy pretty easily, because PointerAddrSpace only needs 24 bits, so we have 8 unused bits still left in that structure.

Just to throw it out there, we should be able to support a larger alignment in ArgFlagsTy pretty easily, because PointerAddrSpace only needs 24 bits, so we have 8 unused bits still left in that structure.

Looks good. Is there any document for the bit size of PointerAddrSpace?

nikic added a comment.Mar 22 2022, 8:13 AM

@LuoYuanke Not sure if this is documented anywhere, but there is this check in the DataLayout implementation: https://github.com/llvm/llvm-project/blob/fea20cb99087208d589d81bb7bbbc84198c7ffa4/llvm/lib/IR/DataLayout.cpp#L250-L256

@LuoYuanke Not sure if this is documented anywhere, but there is this check in the DataLayout implementation: https://github.com/llvm/llvm-project/blob/fea20cb99087208d589d81bb7bbbc84198c7ffa4/llvm/lib/IR/DataLayout.cpp#L250-L256

Thanks, @nikic. I'll come up with a patch to enlarge the alignment bit field.

skan added a comment.Mar 22 2022, 7:18 PM

@LuoYuanke Not sure if this is documented anywhere, but there is this check in the DataLayout implementation: https://github.com/llvm/llvm-project/blob/fea20cb99087208d589d81bb7bbbc84198c7ffa4/llvm/lib/IR/DataLayout.cpp#L250-L256

Thanks, @nikic. I'll come up with a patch to enlarge the alignment bit field.

I would argue that maybe we should shrink the alignment bit field...

Yeah, I don't think it's worth to add one more bit just for avoiding error. We don't have the requirment to store such a large alignment. The OrigAlign is another topic, I think we can leave it as is.

This revision was landed with ongoing or failed builds.Mar 26 2022, 5:46 PM
This revision was automatically updated to reflect the committed changes.

@LuoYuanke Not sure if this is documented anywhere, but there is this check in the DataLayout implementation: https://github.com/llvm/llvm-project/blob/fea20cb99087208d589d81bb7bbbc84198c7ffa4/llvm/lib/IR/DataLayout.cpp#L250-L256

Thanks, @nikic. I'll come up with a patch to enlarge the alignment bit field.

I would argue that maybe we should shrink the alignment bit field...

As seen in https://github.com/llvm/llvm-project/issues/58304, some intrinsics need a parameter with higher alignment (2 << 15). Should we extend the alignment field to accommodate that?

This comment was removed by LuoYuanke.

As seen in https://github.com/llvm/llvm-project/issues/58304, some intrinsics need a parameter with higher alignment (2 << 15). Should we extend the alignment field to accommodate that?

Maybe we can, but it seems an infrastructure change. Not sure what the risk we'd take for the change.

In the case of #58304 it is a @llvm.vector.reduce.or.v16i8488(<16 x i8488> %18) that is incorrectly failing, which is not a real call. Could we exclude intrinsics from this verifier check?

In the case of #58304 it is a @llvm.vector.reduce.or.v16i8488(<16 x i8488> %18) that is incorrectly failing, which is not a real call. Could we exclude intrinsics from this verifier check?

It sounds reasonable to me. Let me create a patch to exclude intrinsics.

I remove the constrain for intrinsics with https://reviews.llvm.org/D136330. However when testing below intrinsics case, it still crashes on DAGISel.

$ cat param-align.ll
define dso_local float @foo(<8192 x float> noundef %vec) {
entry:
  %b = call float @llvm.vector.reduce.fadd.f32.v8192f32(float -0.0, <8192 x float> %vec)
  ret float %b
}

declare float @llvm.vector.reduce.fadd.f32.v8192f32(float %start_value, <8192 x float> %a)
$ llc param-align.ll
llc: /export/users/workspace/opensrc/llvm-project-github/llvm/include/llvm/CodeGen/TargetCallingConv.h:150: void llvm::ISD::ArgFlagsTy::setMemAlign(llvm::Align): Assertion `getNonZeroMemAlign() == A && "bitfield overflow"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.

I remove the constrain for intrinsics with https://reviews.llvm.org/D136330. However when testing below intrinsics case, it still crashes on DAGISel.

$ cat param-align.ll
define dso_local float @foo(<8192 x float> noundef %vec) {
entry:
  %b = call float @llvm.vector.reduce.fadd.f32.v8192f32(float -0.0, <8192 x float> %vec)
  ret float %b
}

declare float @llvm.vector.reduce.fadd.f32.v8192f32(float %start_value, <8192 x float> %a)
$ llc param-align.ll
llc: /export/users/workspace/opensrc/llvm-project-github/llvm/include/llvm/CodeGen/TargetCallingConv.h:150: void llvm::ISD::ArgFlagsTy::setMemAlign(llvm::Align): Assertion `getNonZeroMemAlign() == A && "bitfield overflow"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.

That is presumably because of the <8192 x float> noundef %vec argument for @foo. If it was loaded from a pointer, does it still fail? It will be a pretty huge expansion, but should work OK.

That is presumably because of the <8192 x float> noundef %vec argument for @foo. If it was loaded from a pointer, does it still fail? It will be a pretty huge expansion, but should work OK.

It doesn't fail when <8192 x float> %vec is loaded from a pointer.