// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-globals all --version 6 // RUN: %clang_cc1 -triple wasm64-- -fnative-half-arguments-and-returns -emit-llvm -O1 -disable-llvm-passes -o - %s | FileCheck %s __fp16 g = 2.0f; //. // CHECK: @g = global i16 16384, align 2 //. // CHECK-LABEL: define float @test_memory_fp16_to_float( // CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0:[0-9]+]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8 // CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[__FP16PTR_TBAA5:![0-9]+]] // CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[__FP16PTR_TBAA5]] // CHECK-NEXT: [[TMP1:%.*]] = load i16, ptr [[TMP0]], align 2, !tbaa [[__FP16_TBAA8:![0-9]+]] // CHECK-NEXT: [[TMP2:%.*]] = bitcast i16 [[TMP1]] to half // CHECK-NEXT: [[CONV:%.*]] = fpext half [[TMP2]] to float // CHECK-NEXT: ret float [[CONV]] // float test_memory_fp16_to_float(__fp16 *ptr) { return *ptr; } // CHECK-LABEL: define void @test_memory_float_from_fp16( // CHECK-SAME: ptr noundef [[PTR:%.*]], float noundef [[VAL:%.*]]) #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8 // CHECK-NEXT: [[VAL_ADDR:%.*]] = alloca float, align 4 // CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[__FP16PTR_TBAA5]] // CHECK-NEXT: store float [[VAL]], ptr [[VAL_ADDR]], align 4, !tbaa [[FLOAT_TBAA10:![0-9]+]] // CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[VAL_ADDR]], align 4, !tbaa [[FLOAT_TBAA10]] // CHECK-NEXT: [[CONV:%.*]] = fptrunc float [[TMP0]] to half // CHECK-NEXT: [[TMP1:%.*]] = bitcast half [[CONV]] to i16 // CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[__FP16PTR_TBAA5]] // CHECK-NEXT: store i16 [[TMP1]], ptr [[TMP2]], align 2, !tbaa [[__FP16_TBAA8]] // CHECK-NEXT: ret void // void test_memory_float_from_fp16(__fp16* ptr, float val) { *ptr = val; } // CHECK-LABEL: define float @test_memory_fp16_preinc( // CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8 // CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[__FP16PTR_TBAA5]] // CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[__FP16PTR_TBAA5]] // CHECK-NEXT: [[TMP1:%.*]] = load i16, ptr [[TMP0]], align 2, !tbaa [[__FP16_TBAA8]] // CHECK-NEXT: [[TMP2:%.*]] = bitcast i16 [[TMP1]] to half // CHECK-NEXT: [[INCDEC_CONV:%.*]] = fpext half [[TMP2]] to float // CHECK-NEXT: [[INC:%.*]] = fadd float [[INCDEC_CONV]], 1.000000e+00 // CHECK-NEXT: [[INCDEC_CONV1:%.*]] = fptrunc float [[INC]] to half // CHECK-NEXT: [[TMP3:%.*]] = bitcast half [[INCDEC_CONV1]] to i16 // CHECK-NEXT: store i16 [[TMP3]], ptr [[TMP0]], align 2, !tbaa [[__FP16_TBAA8]] // CHECK-NEXT: [[TMP4:%.*]] = bitcast i16 [[TMP3]] to half // CHECK-NEXT: [[CONV:%.*]] = fpext half [[TMP4]] to float // CHECK-NEXT: ret float [[CONV]] // float test_memory_fp16_preinc(__fp16 *ptr) { return ++(*ptr); } // CHECK-LABEL: define float @test_memory_fp16_postinc( // CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8 // CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[__FP16PTR_TBAA5]] // CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[__FP16PTR_TBAA5]] // CHECK-NEXT: [[TMP1:%.*]] = load i16, ptr [[TMP0]], align 2, !tbaa [[__FP16_TBAA8]] // CHECK-NEXT: [[TMP2:%.*]] = bitcast i16 [[TMP1]] to half // CHECK-NEXT: [[INCDEC_CONV:%.*]] = fpext half [[TMP2]] to float // CHECK-NEXT: [[INC:%.*]] = fadd float [[INCDEC_CONV]], 1.000000e+00 // CHECK-NEXT: [[INCDEC_CONV1:%.*]] = fptrunc float [[INC]] to half // CHECK-NEXT: [[TMP3:%.*]] = bitcast half [[INCDEC_CONV1]] to i16 // CHECK-NEXT: store i16 [[TMP3]], ptr [[TMP0]], align 2, !tbaa [[__FP16_TBAA8]] // CHECK-NEXT: [[TMP4:%.*]] = bitcast i16 [[TMP1]] to half // CHECK-NEXT: [[CONV:%.*]] = fpext half [[TMP4]] to float // CHECK-NEXT: ret float [[CONV]] // float test_memory_fp16_postinc(__fp16 *ptr) { return (*ptr)++; } // CHECK-LABEL: define float @test_memory_fp16_predec( // CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8 // CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[__FP16PTR_TBAA5]] // CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[__FP16PTR_TBAA5]] // CHECK-NEXT: [[TMP1:%.*]] = load i16, ptr [[TMP0]], align 2, !tbaa [[__FP16_TBAA8]] // CHECK-NEXT: [[TMP2:%.*]] = bitcast i16 [[TMP1]] to half // CHECK-NEXT: [[INCDEC_CONV:%.*]] = fpext half [[TMP2]] to float // CHECK-NEXT: [[DEC:%.*]] = fadd float [[INCDEC_CONV]], -1.000000e+00 // CHECK-NEXT: [[INCDEC_CONV1:%.*]] = fptrunc float [[DEC]] to half // CHECK-NEXT: [[TMP3:%.*]] = bitcast half [[INCDEC_CONV1]] to i16 // CHECK-NEXT: store i16 [[TMP3]], ptr [[TMP0]], align 2, !tbaa [[__FP16_TBAA8]] // CHECK-NEXT: [[TMP4:%.*]] = bitcast i16 [[TMP3]] to half // CHECK-NEXT: [[CONV:%.*]] = fpext half [[TMP4]] to float // CHECK-NEXT: ret float [[CONV]] // float test_memory_fp16_predec(__fp16 *ptr) { return --(*ptr); } // CHECK-LABEL: define float @test_memory_fp16_postdec( // CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8 // CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[__FP16PTR_TBAA5]] // CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[__FP16PTR_TBAA5]] // CHECK-NEXT: [[TMP1:%.*]] = load i16, ptr [[TMP0]], align 2, !tbaa [[__FP16_TBAA8]] // CHECK-NEXT: [[TMP2:%.*]] = bitcast i16 [[TMP1]] to half // CHECK-NEXT: [[INCDEC_CONV:%.*]] = fpext half [[TMP2]] to float // CHECK-NEXT: [[DEC:%.*]] = fadd float [[INCDEC_CONV]], -1.000000e+00 // CHECK-NEXT: [[INCDEC_CONV1:%.*]] = fptrunc float [[DEC]] to half // CHECK-NEXT: [[TMP3:%.*]] = bitcast half [[INCDEC_CONV1]] to i16 // CHECK-NEXT: store i16 [[TMP3]], ptr [[TMP0]], align 2, !tbaa [[__FP16_TBAA8]] // CHECK-NEXT: [[TMP4:%.*]] = bitcast i16 [[TMP1]] to half // CHECK-NEXT: [[CONV:%.*]] = fpext half [[TMP4]] to float // CHECK-NEXT: ret float [[CONV]] // float test_memory_fp16_postdec(__fp16 *ptr) { return (*ptr)--; } // CHECK-LABEL: define i16 @test_arg_return( // CHECK-SAME: i16 noundef [[X:%.*]]) #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[X_ADDR:%.*]] = alloca i16, align 2 // CHECK-NEXT: store i16 [[X]], ptr [[X_ADDR]], align 2, !tbaa [[__FP16_TBAA8]] // CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr [[X_ADDR]], align 2, !tbaa [[__FP16_TBAA8]] // CHECK-NEXT: [[TMP1:%.*]] = bitcast i16 [[TMP0]] to half // CHECK-NEXT: [[CONV:%.*]] = fpext half [[TMP1]] to float // CHECK-NEXT: [[TMP2:%.*]] = load i16, ptr [[X_ADDR]], align 2, !tbaa [[__FP16_TBAA8]] // CHECK-NEXT: [[TMP3:%.*]] = bitcast i16 [[TMP2]] to half // CHECK-NEXT: [[CONV1:%.*]] = fpext half [[TMP3]] to float // CHECK-NEXT: [[ADD:%.*]] = fadd float [[CONV]], [[CONV1]] // CHECK-NEXT: [[CONV2:%.*]] = fptrunc float [[ADD]] to half // CHECK-NEXT: [[TMP4:%.*]] = bitcast half [[CONV2]] to i16 // CHECK-NEXT: ret i16 [[TMP4]] // __fp16 test_arg_return(__fp16 x) { return x + x; } //. // CHECK: attributes #[[ATTR0]] = { nounwind "no-trapping-math"="true" "stack-protector-buffer-size"="8" } //. // CHECK: [[META0:![0-9]+]] = !{!"{{.*}}clang version {{.*}}"} // CHECK: [[META1:![0-9]+]] = !{[[META2:![0-9]+]], [[META2]], i64 0} // CHECK: [[META2]] = !{!"int", [[META3:![0-9]+]], i64 0} // CHECK: [[META3]] = !{!"omnipotent char", [[META4:![0-9]+]], i64 0} // CHECK: [[META4]] = !{!"Simple C/C++ TBAA"} // CHECK: [[__FP16PTR_TBAA5]] = !{[[META6:![0-9]+]], [[META6]], i64 0} // CHECK: [[META6]] = !{!"p1 __fp16", [[META7:![0-9]+]], i64 0} // CHECK: [[META7]] = !{!"any pointer", [[META3]], i64 0} // CHECK: [[__FP16_TBAA8]] = !{[[META9:![0-9]+]], [[META9]], i64 0} // CHECK: [[META9]] = !{!"__fp16", [[META3]], i64 0} // CHECK: [[FLOAT_TBAA10]] = !{[[META11:![0-9]+]], [[META11]], i64 0} // CHECK: [[META11]] = !{!"float", [[META3]], i64 0} //.