; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; Test for the conservative assembly handling mode used by KMSAN.
; RUN: opt < %s -msan-kernel=1 -msan-check-access-address=0 -msan-handle-asm-conservative=0 -S -passes=msan 2>&1 | FileCheck %s
; RUN: opt < %s -msan-kernel=1 -msan-check-access-address=0 -msan-handle-asm-conservative=1 -S -passes=msan 2>&1 | FileCheck %s -check-prefixes=CONS

target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "i386-unknown-linux-gnu"

define dso_local i32 @main() sanitize_memory {
; CHECK-LABEL: define dso_local i32 @main(
; CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
; CHECK-NEXT:  [[ENTRY:.*:]]
; CHECK-NEXT:    [[TMP0:%.*]] = call ptr @__msan_get_context_state()
; CHECK-NEXT:    [[PARAM_SHADOW:%.*]] = getelementptr { [100 x i64], [100 x i64], [100 x i64], [100 x i64], i64, [200 x i32], i32, i32 }, ptr [[TMP0]], i32 0, i32 0
; CHECK-NEXT:    [[RETVAL_SHADOW:%.*]] = getelementptr { [100 x i64], [100 x i64], [100 x i64], [100 x i64], i64, [200 x i32], i32, i32 }, ptr [[TMP0]], i32 0, i32 1
; CHECK-NEXT:    [[VA_ARG_SHADOW:%.*]] = getelementptr { [100 x i64], [100 x i64], [100 x i64], [100 x i64], i64, [200 x i32], i32, i32 }, ptr [[TMP0]], i32 0, i32 2
; CHECK-NEXT:    [[VA_ARG_ORIGIN:%.*]] = getelementptr { [100 x i64], [100 x i64], [100 x i64], [100 x i64], i64, [200 x i32], i32, i32 }, ptr [[TMP0]], i32 0, i32 3
; CHECK-NEXT:    [[VA_ARG_OVERFLOW_SIZE:%.*]] = getelementptr { [100 x i64], [100 x i64], [100 x i64], [100 x i64], i64, [200 x i32], i32, i32 }, ptr [[TMP0]], i32 0, i32 4
; CHECK-NEXT:    [[PARAM_ORIGIN:%.*]] = getelementptr { [100 x i64], [100 x i64], [100 x i64], [100 x i64], i64, [200 x i32], i32, i32 }, ptr [[TMP0]], i32 0, i32 5
; CHECK-NEXT:    [[RETVAL_ORIGIN:%.*]] = getelementptr { [100 x i64], [100 x i64], [100 x i64], [100 x i64], i64, [200 x i32], i32, i32 }, ptr [[TMP0]], i32 0, i32 6
; CHECK-NEXT:    [[TMP18:%.*]] = load i64, ptr [[VA_ARG_OVERFLOW_SIZE]], align 8
; CHECK-NEXT:    call void @llvm.donothing()
; CHECK-NEXT:    [[RETVAL:%.*]] = alloca i32, align 4
; CHECK-NEXT:    call void @__msan_poison_alloca(ptr [[RETVAL]], i64 4, ptr @[[GLOB0:[0-9]+]])
; CHECK-NEXT:    [[BIT:%.*]] = alloca i8, align 1
; CHECK-NEXT:    call void @__msan_poison_alloca(ptr [[BIT]], i64 1, ptr @[[GLOB1:[0-9]+]])
; CHECK-NEXT:    [[VALUE:%.*]] = alloca i64, align 8
; CHECK-NEXT:    call void @__msan_poison_alloca(ptr [[VALUE]], i64 8, ptr @[[GLOB2:[0-9]+]])
; CHECK-NEXT:    [[NR:%.*]] = alloca i64, align 8
; CHECK-NEXT:    call void @__msan_poison_alloca(ptr [[NR]], i64 8, ptr @[[GLOB3:[0-9]+]])
; CHECK-NEXT:    [[ADDR:%.*]] = alloca ptr, align 8
; CHECK-NEXT:    call void @__msan_poison_alloca(ptr [[ADDR]], i64 8, ptr @[[GLOB4:[0-9]+]])
; CHECK-NEXT:    [[TMP1:%.*]] = call { ptr, ptr } @__msan_metadata_ptr_for_store_4(ptr [[RETVAL]])
; CHECK-NEXT:    [[TMP2:%.*]] = extractvalue { ptr, ptr } [[TMP1]], 0
; CHECK-NEXT:    [[TMP3:%.*]] = extractvalue { ptr, ptr } [[TMP1]], 1
; CHECK-NEXT:    store i32 0, ptr [[TMP2]], align 4
; CHECK-NEXT:    store i32 0, ptr [[RETVAL]], align 4
; CHECK-NEXT:    [[TMP4:%.*]] = call { ptr, ptr } @__msan_metadata_ptr_for_store_8(ptr [[VALUE]])
; CHECK-NEXT:    [[TMP5:%.*]] = extractvalue { ptr, ptr } [[TMP4]], 0
; CHECK-NEXT:    [[TMP6:%.*]] = extractvalue { ptr, ptr } [[TMP4]], 1
; CHECK-NEXT:    store i64 0, ptr [[TMP5]], align 8
; CHECK-NEXT:    store i64 2, ptr [[VALUE]], align 8
; CHECK-NEXT:    [[TMP7:%.*]] = call { ptr, ptr } @__msan_metadata_ptr_for_store_8(ptr [[NR]])
; CHECK-NEXT:    [[TMP8:%.*]] = extractvalue { ptr, ptr } [[TMP7]], 0
; CHECK-NEXT:    [[TMP9:%.*]] = extractvalue { ptr, ptr } [[TMP7]], 1
; CHECK-NEXT:    store i64 0, ptr [[TMP8]], align 8
; CHECK-NEXT:    store i64 0, ptr [[NR]], align 8
; CHECK-NEXT:    [[TMP10:%.*]] = call { ptr, ptr } @__msan_metadata_ptr_for_store_8(ptr [[ADDR]])
; CHECK-NEXT:    [[TMP11:%.*]] = extractvalue { ptr, ptr } [[TMP10]], 0
; CHECK-NEXT:    [[TMP12:%.*]] = extractvalue { ptr, ptr } [[TMP10]], 1
; CHECK-NEXT:    store i64 0, ptr [[TMP11]], align 8
; CHECK-NEXT:    store ptr [[VALUE]], ptr [[ADDR]], align 8
; CHECK-NEXT:    [[TMP13:%.*]] = load i64, ptr [[NR]], align 8
; CHECK-NEXT:    [[TMP14:%.*]] = call { ptr, ptr } @__msan_metadata_ptr_for_load_8(ptr [[NR]])
; CHECK-NEXT:    [[TMP15:%.*]] = extractvalue { ptr, ptr } [[TMP14]], 0
; CHECK-NEXT:    [[TMP16:%.*]] = extractvalue { ptr, ptr } [[TMP14]], 1
; CHECK-NEXT:    [[_MSLD:%.*]] = load i64, ptr [[TMP15]], align 8
; CHECK-NEXT:    [[TMP17:%.*]] = load i32, ptr [[TMP16]], align 8
; CHECK-NEXT:    [[_MSCMP:%.*]] = icmp ne i64 [[_MSLD]], 0
; CHECK-NEXT:    br i1 [[_MSCMP]], label %[[BB19:.*]], label %[[BB20:.*]], !prof [[PROF1:![0-9]+]]
; CHECK:       [[BB19]]:
; CHECK-NEXT:    call void @__msan_warning(i32 [[TMP17]]) #[[ATTR2:[0-9]+]]
; CHECK-NEXT:    br label %[[BB20]]
; CHECK:       [[BB20]]:
; CHECK-NEXT:    call void asm "btsq $2, $1
; CHECK-NEXT:    [[TMP20:%.*]] = load i8, ptr [[BIT]], align 1
; CHECK-NEXT:    [[TMP21:%.*]] = call { ptr, ptr } @__msan_metadata_ptr_for_load_1(ptr [[BIT]])
; CHECK-NEXT:    [[TMP22:%.*]] = extractvalue { ptr, ptr } [[TMP21]], 0
; CHECK-NEXT:    [[TMP23:%.*]] = extractvalue { ptr, ptr } [[TMP21]], 1
; CHECK-NEXT:    [[_MSLD1:%.*]] = load i8, ptr [[TMP22]], align 1
; CHECK-NEXT:    [[TMP24:%.*]] = load i32, ptr [[TMP23]], align 4
; CHECK-NEXT:    [[_MSPROP:%.*]] = trunc i8 [[_MSLD1]] to i1
; CHECK-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP20]] to i1
; CHECK-NEXT:    br i1 [[_MSPROP]], label %[[BB26:.*]], label %[[BB27:.*]], !prof [[PROF1]]
; CHECK:       [[BB26]]:
; CHECK-NEXT:    call void @__msan_warning(i32 [[TMP24]]) #[[ATTR2]]
; CHECK-NEXT:    br label %[[BB27]]
; CHECK:       [[BB27]]:
; CHECK-NEXT:    br i1 [[TOBOOL]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
; CHECK:       [[IF_THEN]]:
; CHECK-NEXT:    store i32 0, ptr [[RETVAL_SHADOW]], align 8
; CHECK-NEXT:    ret i32 0
; CHECK:       [[IF_ELSE]]:
; CHECK-NEXT:    store i32 0, ptr [[RETVAL_SHADOW]], align 8
; CHECK-NEXT:    ret i32 1
;
; CONS-LABEL: define dso_local i32 @main(
; CONS-SAME: ) #[[ATTR0:[0-9]+]] {
; CONS-NEXT:  [[ENTRY:.*:]]
; CONS-NEXT:    [[TMP0:%.*]] = call ptr @__msan_get_context_state()
; CONS-NEXT:    [[PARAM_SHADOW:%.*]] = getelementptr { [100 x i64], [100 x i64], [100 x i64], [100 x i64], i64, [200 x i32], i32, i32 }, ptr [[TMP0]], i32 0, i32 0
; CONS-NEXT:    [[RETVAL_SHADOW:%.*]] = getelementptr { [100 x i64], [100 x i64], [100 x i64], [100 x i64], i64, [200 x i32], i32, i32 }, ptr [[TMP0]], i32 0, i32 1
; CONS-NEXT:    [[VA_ARG_SHADOW:%.*]] = getelementptr { [100 x i64], [100 x i64], [100 x i64], [100 x i64], i64, [200 x i32], i32, i32 }, ptr [[TMP0]], i32 0, i32 2
; CONS-NEXT:    [[VA_ARG_ORIGIN:%.*]] = getelementptr { [100 x i64], [100 x i64], [100 x i64], [100 x i64], i64, [200 x i32], i32, i32 }, ptr [[TMP0]], i32 0, i32 3
; CONS-NEXT:    [[VA_ARG_OVERFLOW_SIZE:%.*]] = getelementptr { [100 x i64], [100 x i64], [100 x i64], [100 x i64], i64, [200 x i32], i32, i32 }, ptr [[TMP0]], i32 0, i32 4
; CONS-NEXT:    [[PARAM_ORIGIN:%.*]] = getelementptr { [100 x i64], [100 x i64], [100 x i64], [100 x i64], i64, [200 x i32], i32, i32 }, ptr [[TMP0]], i32 0, i32 5
; CONS-NEXT:    [[RETVAL_ORIGIN:%.*]] = getelementptr { [100 x i64], [100 x i64], [100 x i64], [100 x i64], i64, [200 x i32], i32, i32 }, ptr [[TMP0]], i32 0, i32 6
; CONS-NEXT:    [[TMP18:%.*]] = load i64, ptr [[VA_ARG_OVERFLOW_SIZE]], align 8
; CONS-NEXT:    call void @llvm.donothing()
; CONS-NEXT:    [[RETVAL:%.*]] = alloca i32, align 4
; CONS-NEXT:    call void @__msan_poison_alloca(ptr [[RETVAL]], i64 4, ptr @[[GLOB0:[0-9]+]])
; CONS-NEXT:    [[BIT:%.*]] = alloca i8, align 1
; CONS-NEXT:    call void @__msan_poison_alloca(ptr [[BIT]], i64 1, ptr @[[GLOB1:[0-9]+]])
; CONS-NEXT:    [[VALUE:%.*]] = alloca i64, align 8
; CONS-NEXT:    call void @__msan_poison_alloca(ptr [[VALUE]], i64 8, ptr @[[GLOB2:[0-9]+]])
; CONS-NEXT:    [[NR:%.*]] = alloca i64, align 8
; CONS-NEXT:    call void @__msan_poison_alloca(ptr [[NR]], i64 8, ptr @[[GLOB3:[0-9]+]])
; CONS-NEXT:    [[ADDR:%.*]] = alloca ptr, align 8
; CONS-NEXT:    call void @__msan_poison_alloca(ptr [[ADDR]], i64 8, ptr @[[GLOB4:[0-9]+]])
; CONS-NEXT:    [[TMP1:%.*]] = call { ptr, ptr } @__msan_metadata_ptr_for_store_4(ptr [[RETVAL]])
; CONS-NEXT:    [[TMP2:%.*]] = extractvalue { ptr, ptr } [[TMP1]], 0
; CONS-NEXT:    [[TMP3:%.*]] = extractvalue { ptr, ptr } [[TMP1]], 1
; CONS-NEXT:    store i32 0, ptr [[TMP2]], align 4
; CONS-NEXT:    store i32 0, ptr [[RETVAL]], align 4
; CONS-NEXT:    [[TMP4:%.*]] = call { ptr, ptr } @__msan_metadata_ptr_for_store_8(ptr [[VALUE]])
; CONS-NEXT:    [[TMP5:%.*]] = extractvalue { ptr, ptr } [[TMP4]], 0
; CONS-NEXT:    [[TMP6:%.*]] = extractvalue { ptr, ptr } [[TMP4]], 1
; CONS-NEXT:    store i64 0, ptr [[TMP5]], align 8
; CONS-NEXT:    store i64 2, ptr [[VALUE]], align 8
; CONS-NEXT:    [[TMP7:%.*]] = call { ptr, ptr } @__msan_metadata_ptr_for_store_8(ptr [[NR]])
; CONS-NEXT:    [[TMP8:%.*]] = extractvalue { ptr, ptr } [[TMP7]], 0
; CONS-NEXT:    [[TMP9:%.*]] = extractvalue { ptr, ptr } [[TMP7]], 1
; CONS-NEXT:    store i64 0, ptr [[TMP8]], align 8
; CONS-NEXT:    store i64 0, ptr [[NR]], align 8
; CONS-NEXT:    [[TMP10:%.*]] = call { ptr, ptr } @__msan_metadata_ptr_for_store_8(ptr [[ADDR]])
; CONS-NEXT:    [[TMP11:%.*]] = extractvalue { ptr, ptr } [[TMP10]], 0
; CONS-NEXT:    [[TMP12:%.*]] = extractvalue { ptr, ptr } [[TMP10]], 1
; CONS-NEXT:    store i64 0, ptr [[TMP11]], align 8
; CONS-NEXT:    store ptr [[VALUE]], ptr [[ADDR]], align 8
; CONS-NEXT:    [[TMP13:%.*]] = load i64, ptr [[NR]], align 8
; CONS-NEXT:    [[TMP14:%.*]] = call { ptr, ptr } @__msan_metadata_ptr_for_load_8(ptr [[NR]])
; CONS-NEXT:    [[TMP15:%.*]] = extractvalue { ptr, ptr } [[TMP14]], 0
; CONS-NEXT:    [[TMP16:%.*]] = extractvalue { ptr, ptr } [[TMP14]], 1
; CONS-NEXT:    [[_MSLD:%.*]] = load i64, ptr [[TMP15]], align 8
; CONS-NEXT:    [[TMP17:%.*]] = load i32, ptr [[TMP16]], align 8
; CONS-NEXT:    call void @__msan_instrument_asm_store(ptr [[BIT]], i64 1)
; CONS-NEXT:    call void @__msan_instrument_asm_store(ptr [[ADDR]], i64 8)
; CONS-NEXT:    [[_MSCMP:%.*]] = icmp ne i64 [[_MSLD]], 0
; CONS-NEXT:    br i1 [[_MSCMP]], label %[[BB19:.*]], label %[[BB20:.*]], !prof [[PROF1:![0-9]+]]
; CONS:       [[BB19]]:
; CONS-NEXT:    call void @__msan_warning(i32 [[TMP17]]) #[[ATTR2:[0-9]+]]
; CONS-NEXT:    br label %[[BB20]]
; CONS:       [[BB20]]:
; CONS-NEXT:    call void asm "btsq $2, $1
; CONS-NEXT:    [[TMP20:%.*]] = load i8, ptr [[BIT]], align 1
; CONS-NEXT:    [[TMP21:%.*]] = call { ptr, ptr } @__msan_metadata_ptr_for_load_1(ptr [[BIT]])
; CONS-NEXT:    [[TMP22:%.*]] = extractvalue { ptr, ptr } [[TMP21]], 0
; CONS-NEXT:    [[TMP23:%.*]] = extractvalue { ptr, ptr } [[TMP21]], 1
; CONS-NEXT:    [[_MSLD1:%.*]] = load i8, ptr [[TMP22]], align 1
; CONS-NEXT:    [[TMP24:%.*]] = load i32, ptr [[TMP23]], align 4
; CONS-NEXT:    [[_MSPROP:%.*]] = trunc i8 [[_MSLD1]] to i1
; CONS-NEXT:    [[TOBOOL:%.*]] = trunc i8 [[TMP20]] to i1
; CONS-NEXT:    br i1 [[_MSPROP]], label %[[BB26:.*]], label %[[BB27:.*]], !prof [[PROF1]]
; CONS:       [[BB26]]:
; CONS-NEXT:    call void @__msan_warning(i32 [[TMP24]]) #[[ATTR2]]
; CONS-NEXT:    br label %[[BB27]]
; CONS:       [[BB27]]:
; CONS-NEXT:    br i1 [[TOBOOL]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
; CONS:       [[IF_THEN]]:
; CONS-NEXT:    store i32 0, ptr [[RETVAL_SHADOW]], align 8
; CONS-NEXT:    ret i32 0
; CONS:       [[IF_ELSE]]:
; CONS-NEXT:    store i32 0, ptr [[RETVAL_SHADOW]], align 8
; CONS-NEXT:    ret i32 1
;
entry:
  %retval = alloca i32, align 4
  %bit = alloca i8, align 1
  %value = alloca i64, align 8
  %nr = alloca i64, align 8
  %addr = alloca ptr, align 8
  store i32 0, ptr %retval, align 4
  store i64 2, ptr %value, align 8
  store i64 0, ptr %nr, align 8
  store ptr %value, ptr %addr, align 8
  %0 = load i64, ptr %nr, align 8
  call void asm "btsq $2, $1; setc $0", "=*qm,=*m,Ir,~{dirflag},~{fpsr},~{flags}"(ptr elementtype(i8) %bit, ptr elementtype(ptr) %addr, i64 %0)
  %1 = load i8, ptr %bit, align 1
  %tobool = trunc i8 %1 to i1
  br i1 %tobool, label %if.then, label %if.else

if.then:                                          ; preds = %entry
  ret i32 0

if.else:                                          ; preds = %entry
  ret i32 1
}
;.
; CHECK: [[PROF1]] = !{!"branch_weights", i32 1, i32 1048575}
;.
; CONS: [[PROF1]] = !{!"branch_weights", i32 1, i32 1048575}
;.
