Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SR-13106] "isvolatile argument of memory intrinsics must be a constant int" when compiling UnsafeRawPointer #55552

Closed
swift-ci opened this issue Jun 28, 2020 · 7 comments
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself

Comments

@swift-ci
Copy link
Collaborator

Previous ID SR-13106
Radar rdar://problem/64861873
Original Reporter carlos4242 (JIRA User)
Type Bug
Status Closed
Resolution Invalid
Environment

macOS 10.15.5, compiler is

Apple clang version 11.0.3 (clang-1103.0.32.62) installed as part of Xcode 11.5

swift built from https://github.com/carlos4242/swift/tree/SR-13095-test using ninja

Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Bug
Assignee None
Priority Medium

md5: 89fcaeb3e5abce0c94d16277e9b8ed76

Issue Description:

More work on my custom standard library. I'm compiling using this command...

/path/to/my/custom/swift -frontend -emit-ir ...other swift files... -primary-file UnsafeRawPointer.swift ...other swift files... -disable-objc-attr-requires-foundation-module -target avr-atmel-linux-gnueabihf -disable-objc-interop -parse-as-library -parse-stdlib -module-name Swift -o UnsafeRawPointer.ll

And the method being compiled is...

  @inlinable
  public func storeBytes<T>(
    of value: T, toByteOffset offset: Int = 0, as type: T.Type
  ) {
    var temp = value
    withUnsafeMutablePointer(to: &temp) { source in
      let rawSrc = UnsafeMutableRawPointer(source)._rawValue
      Builtin.int_memcpy_RawPointer_RawPointer_Int64(
        (self + offset)._rawValue, rawSrc, UInt64(MemoryLayout<T>.size)._value,
        /*volatile:*/ false._value)
    }
  }

Bool is defined as usual in my stdlib...

@frozen
public struct Bool {
  @usableFromInline
  internal var _value: Builtin.Int1

  @_transparent
  public init() {
    let zero: Int8 = 0
    self._value = Builtin.trunc_Int8_Int1(zero._value)
  }

  @usableFromInline @_transparent
  internal init(_ v: Builtin.Int1) { self._value = v }
  
  @inlinable
  public init(_ value: Bool) {
    self = value
  }
}

The error I'm getting is...

isvolatile argument of memory intrinsics must be a constant int
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %19, i8* %0, i64 %26, i1 %28)
in function $sSv10storeBytes2of12toByteOffset2asyx_SixmtlFySpyxGXEfU_
<unknown>:0: error: fatal error encountered during compilation; please file a bug report with your project and the crash log
<unknown>:0: note: Broken function found, compilation aborted!

It looks like compilation is fine through parse, AST, Sema, SIL generation and optimisation (probably), then during IRGen, the function being written is passed through custom LLVM passes, including verification. At that point, internal checks in LLVM detect that the emitted code is invalid and trap.

Putting in breakpoints and examining the IR shows the problem with the LLVM IR that swift is generating...

(lldb) e F.dump()


define linkonce_odr hidden swiftcc void @"$sSv10storeBytes2of12toByteOffset2asyx_SixmtlFySpyxGXEfU_"(i8*, i8*, i16, %swift.type* %T) #&#8203;0 {
entry:
  %3 = alloca %TSv, align 2
  %4 = alloca %TSv, align 2
  %5 = alloca %TSi, align 2
  %6 = alloca %Ts6UInt64V, align 8
  %7 = alloca %TSi, align 2
  %8 = bitcast %TSv* %3 to i8*
  call void @llvm.lifetime.start.p0i8(i64 2, i8* %8)
  %9 = bitcast %TSv* %4 to i8*
  call void @llvm.lifetime.start.p0i8(i64 2, i8* %9)
  %._rawValue = getelementptr inbounds %TSv, %TSv* %4, i32 0, i32 0
  store i8* %1, i8** %._rawValue, align 2
  %10 = bitcast %TSi* %5 to i8*
  call void @llvm.lifetime.start.p0i8(i64 2, i8* %10)
  %._value = getelementptr inbounds %TSi, %TSi* %5, i32 0, i32 0
  store i16 %2, i16* %._value, align 2
  %11 = bitcast %TSv* %3 to %swift.opaque*
  %12 = bitcast %TSv* %4 to %swift.opaque*
  %13 = bitcast %TSi* %5 to %swift.opaque*
  call swiftcc void @"$sSxss8_PointerRzrlE1poiyxx_6StrideQztFZ"(%swift.opaque* noalias nocapture sret %11, %swift.opaque* noalias nocapture %12, %swift.opaque* noalias nocapture %13, %swift.type* bitcast (i16* getelementptr inbounds (<{ i8**, i16, <{ i32, i16, i16, i16, i16, i32, i32 }>*, i32 }>, <{ i8**, i16, <{ i32, i16, i16, i16, i16, i32, i32 }>*, i32 }>* @"$sSvMf", i32 0, i32 1) to %swift.type*), i8** getelementptr inbounds ([6 x i8*], [6 x i8*]* @"$sSvs8_PointersWP", i32 0, i32 0), %swift.type* swiftself bitcast (i16* getelementptr inbounds (<{ i8**, i16, <{ i32, i16, i16, i16, i16, i32, i32 }>*, i32 }>, <{ i8**, i16, <{ i32, i16, i16, i16, i16, i32, i32 }>*, i32 }>* @"$sSvMf", i32 0, i32 1) to %swift.type*))
  %14 = bitcast %TSi* %5 to i8*
  call void @llvm.lifetime.end.p0i8(i64 2, i8* %14)
  %15 = bitcast %TSv* %4 to i8*
  call void @llvm.lifetime.end.p0i8(i64 2, i8* %15)
  %._rawValue1 = getelementptr inbounds %TSv, %TSv* %3, i32 0, i32 0
  %16 = load i8*, i8** %._rawValue1, align 2
  %17 = bitcast %Ts6UInt64V* %6 to i8*
  call void @llvm.lifetime.start.p0i8(i64 8, i8* %17)
  %18 = call swiftcc i16 @"$ss12MemoryLayoutO4sizeSivgZ"(%swift.type* %T)
  %19 = bitcast %TSi* %7 to i8*
  call void @llvm.lifetime.start.p0i8(i64 2, i8* %19)
  %._value2 = getelementptr inbounds %TSi, %TSi* %7, i32 0, i32 0
  store i16 %18, i16* %._value2, align 2
  %20 = bitcast %Ts6UInt64V* %6 to %swift.opaque*
  %21 = bitcast %TSi* %7 to %swift.opaque*
  call swiftcc void @"$sSUss17FixedWidthIntegerRzrlEyxqd__cSzRd__lufC"(%swift.opaque* noalias nocapture sret %20, %swift.opaque* noalias nocapture %21, %swift.type* @"$ss6UInt64VN", %swift.type* @"$sSiN", i8** @"$ss6UInt64Vs17FixedWidthIntegersWP", i8** @"$ss6UInt64VSUsWP", i8** @"$sSiSzsWP", %swift.type* swiftself @"$ss6UInt64VN")
  %22 = bitcast %TSi* %7 to i8*
  call void @llvm.lifetime.end.p0i8(i64 2, i8* %22)
  %._value3 = getelementptr inbounds %Ts6UInt64V, %Ts6UInt64V* %6, i32 0, i32 0
  %23 = load i64, i64* %._value3, align 8
  %24 = call swiftcc i1 @"$sSb22_builtinBooleanLiteralSbBi1__tcfC"(i1 false)
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %16, i8* %0, i64 %23, i1 %24)
  %25 = bitcast %Ts6UInt64V* %6 to i8*
  call void @llvm.lifetime.end.p0i8(i64 8, i8* %25)
  %26 = bitcast %TSv* %3 to i8*
  call void @llvm.lifetime.end.p0i8(i64 2, i8* %26)
  ret void
}

The call site for the intrinsic memcpy is wrong...

%24 = call swiftcc i1 @"$sSb22_builtinBooleanLiteralSbBi1__tcfC"(i1 false)   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %16, i8* %0, i64 %23, i1 %24)

This should have been optimised away to...

call void @llvm.memcpy.p0i8.p0i8.i64(i8* %16, i8* %0, i64 %23, i1 false)

What I would have expected was sSb22_builtinBooleanLiteralSbBi1__tcfC and the subsequent _value access should have been inlined, then by constant propagation, the code eliminated and false passed as the final parameter to the memcpy intrinsic.

If it's useful, later this afternoon (UK time) I'll raise a feeback assistant ticket with the full code as I did with my previous ticket.

In the meantime, if anyone can immediately see what's wrong, I'd welcome the feedback!

@swift-ci
Copy link
Collaborator Author

Comment by Carl Peto (JIRA)

Feedback assistant issue raised with ID FB7814621. All required files and instructions to reproduce the issue attached to that.

@eeckstein
Copy link
Member

carlos4242 (JIRA User) What's going wrong here is that the Bool initializer is not inlined (though it's defined as "transparent").
It looks like the problem is that you are compiling the stdlib not in whole-module mode. The compile command line should not contain a "-primary-file". I think non-whole-module mode just does not work for the stdlib.

@swift-ci
Copy link
Collaborator Author

Comment by Carl Peto (JIRA)

That sounds like sense.

I can try it with -wmo. A bit of retooling needed but not too bad.

A couple of dumb questions:

1) wmo looks like it does optimisation, for example SIL transforms, across swift files. Is this the same as link-time-optimisation or are they unrelated?

2) Is it possible to compile stdlib in whole module optimisation mode and still emit the result to IR? I depend on that workflow because I'm using a separate llc compiler to make object code from llvm IR.

Thanks

Carl

@swift-ci
Copy link
Collaborator Author

Comment by Carl Peto (JIRA)

update: i think i'll end up answering my own questions... it looks like it is not the same as LTO, and it looks like it's possible to emit the files as IR still. The documentation you pointed to explicitly points out that each unit is compiled to LLVM IR in memory at least, even when taken as a whole they're optimised together.

basically your fixed seems to have worked in this case of Bool code... the accessor wasn't getting inlined properly until I turned on "-whole-module-optimisation", now it's compiling. On to the next issue!

Thanks 🙂

@typesanitizer
Copy link

Marking the issue as resolved since it looks like the problem was due to a misconfiguration, which has been fixed. Please mark it as closed if that's correct. 🙂

@swift-ci
Copy link
Collaborator Author

Comment by Carl Peto (JIRA)

Looks good

@eeckstein
Copy link
Member

👍

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself
Projects
None yet
Development

No branches or pull requests

3 participants