1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes 2; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM 3; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM 4; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM 5; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM 6target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 7 8; Test cases designed for the nosync function attribute. 9; FIXME's are used to indicate problems and missing attributes. 10 11; struct RT { 12; char A; 13; int B[10][20]; 14; char C; 15; }; 16; struct ST { 17; int X; 18; double Y; 19; struct RT Z; 20; }; 21; 22; int *foo(struct ST *s) { 23; return &s[1].Z.B[5][13]; 24; } 25 26; TEST 1 27; non-convergent and readnone implies nosync 28%struct.RT = type { i8, [10 x [20 x i32]], i8 } 29%struct.ST = type { i32, double, %struct.RT } 30 31; IS__TUNIT____: Function Attrs: nofree nosync nounwind optsize readnone ssp uwtable 32; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind optsize readnone ssp uwtable 33define i32* @foo(%struct.ST* %s) nounwind uwtable readnone optsize ssp { 34; CHECK-LABEL: define {{[^@]+}}@foo 35; CHECK-SAME: (%struct.ST* nofree readnone "no-capture-maybe-returned" [[S:%.*]]) 36; CHECK-NEXT: entry: 37; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [[STRUCT_ST:%.*]], %struct.ST* [[S]], i64 1, i32 2, i32 1, i64 5, i64 13 38; CHECK-NEXT: ret i32* [[ARRAYIDX]] 39; 40entry: 41 %arrayidx = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 1, i32 2, i32 1, i64 5, i64 13 42 ret i32* %arrayidx 43} 44 45; TEST 2 46; atomic load with monotonic ordering 47; int load_monotonic(_Atomic int *num) { 48; int n = atomic_load_explicit(num, memory_order_relaxed); 49; return n; 50; } 51 52; IS__TUNIT____: Function Attrs: argmemonly nofree norecurse nosync nounwind uwtable 53; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nosync nounwind uwtable 54define i32 @load_monotonic(i32* nocapture readonly %0) norecurse nounwind uwtable { 55; CHECK-LABEL: define {{[^@]+}}@load_monotonic 56; CHECK-SAME: (i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[TMP0:%.*]]) 57; CHECK-NEXT: [[TMP2:%.*]] = load atomic i32, i32* [[TMP0]] monotonic, align 4 58; CHECK-NEXT: ret i32 [[TMP2]] 59; 60 %2 = load atomic i32, i32* %0 monotonic, align 4 61 ret i32 %2 62} 63 64 65; TEST 3 66; atomic store with monotonic ordering. 67; void store_monotonic(_Atomic int *num) { 68; atomic_load_explicit(num, memory_order_relaxed); 69; } 70 71; IS__TUNIT____: Function Attrs: argmemonly nofree norecurse nosync nounwind uwtable 72; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nosync nounwind uwtable 73define void @store_monotonic(i32* nocapture %0) norecurse nounwind uwtable { 74; CHECK-LABEL: define {{[^@]+}}@store_monotonic 75; CHECK-SAME: (i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[TMP0:%.*]]) 76; CHECK-NEXT: store atomic i32 10, i32* [[TMP0]] monotonic, align 4 77; CHECK-NEXT: ret void 78; 79 store atomic i32 10, i32* %0 monotonic, align 4 80 ret void 81} 82 83; TEST 4 - negative, should not deduce nosync 84; atomic load with acquire ordering. 85; int load_acquire(_Atomic int *num) { 86; int n = atomic_load_explicit(num, memory_order_acquire); 87; return n; 88; } 89 90; IS__TUNIT____: Function Attrs: argmemonly nofree norecurse nounwind uwtable 91; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nounwind uwtable 92; CHECK-NOT: nosync 93define i32 @load_acquire(i32* nocapture readonly %0) norecurse nounwind uwtable { 94; CHECK-LABEL: define {{[^@]+}}@load_acquire 95; CHECK-SAME: (i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[TMP0:%.*]]) 96; CHECK-NEXT: [[TMP2:%.*]] = load atomic i32, i32* [[TMP0]] acquire, align 4 97; CHECK-NEXT: ret i32 [[TMP2]] 98; 99 %2 = load atomic i32, i32* %0 acquire, align 4 100 ret i32 %2 101} 102 103; TEST 5 - negative, should not deduce nosync 104; atomic load with release ordering 105; void load_release(_Atomic int *num) { 106; atomic_store_explicit(num, 10, memory_order_release); 107; } 108 109; IS__TUNIT____: Function Attrs: argmemonly nofree norecurse nounwind uwtable 110; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nounwind uwtable 111; CHECK-NOT: nosync 112define void @load_release(i32* nocapture %0) norecurse nounwind uwtable { 113; CHECK-LABEL: define {{[^@]+}}@load_release 114; CHECK-SAME: (i32* nocapture nofree writeonly align 4 [[TMP0:%.*]]) 115; CHECK-NEXT: store atomic volatile i32 10, i32* [[TMP0]] release, align 4 116; CHECK-NEXT: ret void 117; 118 store atomic volatile i32 10, i32* %0 release, align 4 119 ret void 120} 121 122; TEST 6 - negative volatile, relaxed atomic 123 124; IS__TUNIT____: Function Attrs: argmemonly nofree norecurse nounwind uwtable 125; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nounwind uwtable 126; CHECK-NOT: nosync 127define void @load_volatile_release(i32* nocapture %0) norecurse nounwind uwtable { 128; CHECK-LABEL: define {{[^@]+}}@load_volatile_release 129; CHECK-SAME: (i32* nocapture nofree writeonly align 4 [[TMP0:%.*]]) 130; CHECK-NEXT: store atomic volatile i32 10, i32* [[TMP0]] release, align 4 131; CHECK-NEXT: ret void 132; 133 store atomic volatile i32 10, i32* %0 release, align 4 134 ret void 135} 136 137; TEST 7 - negative, should not deduce nosync 138; volatile store. 139; void volatile_store(volatile int *num) { 140; *num = 14; 141; } 142 143; IS__TUNIT____: Function Attrs: argmemonly nofree norecurse nounwind uwtable 144; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nounwind uwtable 145; CHECK-NOT: nosync 146define void @volatile_store(i32* %0) norecurse nounwind uwtable { 147; CHECK-LABEL: define {{[^@]+}}@volatile_store 148; CHECK-SAME: (i32* nofree align 4 [[TMP0:%.*]]) 149; CHECK-NEXT: store volatile i32 14, i32* [[TMP0]], align 4 150; CHECK-NEXT: ret void 151; 152 store volatile i32 14, i32* %0, align 4 153 ret void 154} 155 156; TEST 8 - negative, should not deduce nosync 157; volatile load. 158; int volatile_load(volatile int *num) { 159; int n = *num; 160; return n; 161; } 162 163; IS__TUNIT____: Function Attrs: argmemonly nofree norecurse nounwind uwtable 164; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nounwind uwtable 165; CHECK-NOT: nosync 166define i32 @volatile_load(i32* %0) norecurse nounwind uwtable { 167; CHECK-LABEL: define {{[^@]+}}@volatile_load 168; CHECK-SAME: (i32* nofree align 4 [[TMP0:%.*]]) 169; CHECK-NEXT: [[TMP2:%.*]] = load volatile i32, i32* [[TMP0]], align 4 170; CHECK-NEXT: ret i32 [[TMP2]] 171; 172 %2 = load volatile i32, i32* %0, align 4 173 ret i32 %2 174} 175 176; TEST 9 177 178; CHECK: Function Attrs: noinline nosync nounwind uwtable 179; CHECK-NEXT: declare void @nosync_function() 180declare void @nosync_function() noinline nounwind uwtable nosync 181 182; IS__TUNIT____: Function Attrs: noinline nosync nounwind uwtable 183; IS__CGSCC____: Function Attrs: noinline nosync nounwind uwtable 184define void @call_nosync_function() nounwind uwtable noinline { 185; CHECK-LABEL: define {{[^@]+}}@call_nosync_function() 186; CHECK-NEXT: tail call void @nosync_function() 187; CHECK-NEXT: ret void 188; 189 tail call void @nosync_function() noinline nounwind uwtable 190 ret void 191} 192 193; TEST 10 - negative, should not deduce nosync 194 195; CHECK: Function Attrs: noinline nounwind uwtable 196; CHECK-NEXT: declare void @might_sync() 197declare void @might_sync() noinline nounwind uwtable 198 199; IS__TUNIT____: Function Attrs: noinline nounwind uwtable 200; IS__CGSCC____: Function Attrs: noinline nounwind uwtable 201; CHECK-NOT: nosync 202define void @call_might_sync() nounwind uwtable noinline { 203; CHECK-LABEL: define {{[^@]+}}@call_might_sync() 204; CHECK-NEXT: tail call void @might_sync() 205; CHECK-NEXT: ret void 206; 207 tail call void @might_sync() noinline nounwind uwtable 208 ret void 209} 210 211; TEST 11 - positive, should deduce nosync 212; volatile operation in same scc but dead. Call volatile_load defined in TEST 8. 213 214; IS__TUNIT____: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable 215; IS__CGSCC_OPM: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable 216; IS__CGSCC_NPM: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable 217define i32 @scc1(i32* %0) noinline nounwind uwtable { 218; CHECK-LABEL: define {{[^@]+}}@scc1 219; CHECK-SAME: (i32* nocapture nofree readnone [[TMP0:%.*]]) 220; CHECK-NEXT: unreachable 221; 222 tail call void @scc2(i32* %0); 223 %val = tail call i32 @volatile_load(i32* %0); 224 ret i32 %val; 225} 226 227; IS__TUNIT____: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable 228; IS__CGSCC_OPM: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable 229; IS__CGSCC_NPM: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable 230define void @scc2(i32* %0) noinline nounwind uwtable { 231; CHECK-LABEL: define {{[^@]+}}@scc2 232; CHECK-SAME: (i32* nocapture nofree readnone [[TMP0:%.*]]) 233; CHECK-NEXT: unreachable 234; 235 tail call i32 @scc1(i32* %0); 236 ret void; 237} 238 239; TEST 12 - fences, negative 240; 241; void foo1(int *a, std::atomic<bool> flag){ 242; *a = 100; 243; atomic_thread_fence(std::memory_order_release); 244; flag.store(true, std::memory_order_relaxed); 245; } 246; 247; void bar(int *a, std::atomic<bool> flag){ 248; while(!flag.load(std::memory_order_relaxed)) 249; ; 250; 251; atomic_thread_fence(std::memory_order_acquire); 252; int b = *a; 253; } 254 255%"struct.std::atomic" = type { %"struct.std::__atomic_base" } 256%"struct.std::__atomic_base" = type { i8 } 257 258; CHECK-NOT: nosync 259define void @foo1(i32* %0, %"struct.std::atomic"* %1) { 260; CHECK-LABEL: define {{[^@]+}}@foo1 261; CHECK-SAME: (i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[TMP0:%.*]], %"struct.std::atomic"* nocapture nofree nonnull writeonly dereferenceable(1) [[TMP1:%.*]]) 262; CHECK-NEXT: store i32 100, i32* [[TMP0]], align 4 263; CHECK-NEXT: fence release 264; CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* [[TMP1]], i64 0, i32 0, i32 0 265; CHECK-NEXT: store atomic i8 1, i8* [[TMP3]] monotonic, align 1 266; CHECK-NEXT: ret void 267; 268 store i32 100, i32* %0, align 4 269 fence release 270 %3 = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* %1, i64 0, i32 0, i32 0 271 store atomic i8 1, i8* %3 monotonic, align 1 272 ret void 273} 274 275; CHECK-NOT: nosync 276define void @bar(i32* %0, %"struct.std::atomic"* %1) { 277; CHECK-LABEL: define {{[^@]+}}@bar 278; CHECK-SAME: (i32* nocapture nofree readnone [[TMP0:%.*]], %"struct.std::atomic"* nocapture nofree nonnull readonly dereferenceable(1) [[TMP1:%.*]]) 279; CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* [[TMP1]], i64 0, i32 0, i32 0 280; CHECK-NEXT: br label [[TMP4:%.*]] 281; CHECK: 4: 282; CHECK-NEXT: [[TMP5:%.*]] = load atomic i8, i8* [[TMP3]] monotonic, align 1 283; CHECK-NEXT: [[TMP6:%.*]] = and i8 [[TMP5]], 1 284; CHECK-NEXT: [[TMP7:%.*]] = icmp eq i8 [[TMP6]], 0 285; CHECK-NEXT: br i1 [[TMP7]], label [[TMP4]], label [[TMP8:%.*]] 286; CHECK: 8: 287; CHECK-NEXT: fence acquire 288; CHECK-NEXT: ret void 289; 290 %3 = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* %1, i64 0, i32 0, i32 0 291 br label %4 292 2934: ; preds = %4, %2 294 %5 = load atomic i8, i8* %3 monotonic, align 1 295 %6 = and i8 %5, 1 296 %7 = icmp eq i8 %6, 0 297 br i1 %7, label %4, label %8 298 2998: ; preds = %4 300 fence acquire 301 ret void 302} 303 304; TEST 13 - Fence syncscope("singlethread") seq_cst 305; IS__TUNIT____: Function Attrs: nofree nosync nounwind willreturn 306; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind willreturn 307define void @foo1_singlethread(i32* %0, %"struct.std::atomic"* %1) { 308; CHECK-LABEL: define {{[^@]+}}@foo1_singlethread 309; CHECK-SAME: (i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[TMP0:%.*]], %"struct.std::atomic"* nocapture nofree nonnull writeonly dereferenceable(1) [[TMP1:%.*]]) 310; CHECK-NEXT: store i32 100, i32* [[TMP0]], align 4 311; CHECK-NEXT: fence syncscope("singlethread") release 312; CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* [[TMP1]], i64 0, i32 0, i32 0 313; CHECK-NEXT: store atomic i8 1, i8* [[TMP3]] monotonic, align 1 314; CHECK-NEXT: ret void 315; 316 store i32 100, i32* %0, align 4 317 fence syncscope("singlethread") release 318 %3 = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* %1, i64 0, i32 0, i32 0 319 store atomic i8 1, i8* %3 monotonic, align 1 320 ret void 321} 322 323; IS__TUNIT____: Function Attrs: nofree nosync nounwind 324; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind 325define void @bar_singlethread(i32* %0, %"struct.std::atomic"* %1) { 326; CHECK-LABEL: define {{[^@]+}}@bar_singlethread 327; CHECK-SAME: (i32* nocapture nofree readnone [[TMP0:%.*]], %"struct.std::atomic"* nocapture nofree nonnull readonly dereferenceable(1) [[TMP1:%.*]]) 328; CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* [[TMP1]], i64 0, i32 0, i32 0 329; CHECK-NEXT: br label [[TMP4:%.*]] 330; CHECK: 4: 331; CHECK-NEXT: [[TMP5:%.*]] = load atomic i8, i8* [[TMP3]] monotonic, align 1 332; CHECK-NEXT: [[TMP6:%.*]] = and i8 [[TMP5]], 1 333; CHECK-NEXT: [[TMP7:%.*]] = icmp eq i8 [[TMP6]], 0 334; CHECK-NEXT: br i1 [[TMP7]], label [[TMP4]], label [[TMP8:%.*]] 335; CHECK: 8: 336; CHECK-NEXT: fence syncscope("singlethread") acquire 337; CHECK-NEXT: ret void 338; 339 %3 = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* %1, i64 0, i32 0, i32 0 340 br label %4 341 3424: ; preds = %4, %2 343 %5 = load atomic i8, i8* %3 monotonic, align 1 344 %6 = and i8 %5, 1 345 %7 = icmp eq i8 %6, 0 346 br i1 %7, label %4, label %8 347 3488: ; preds = %4 349 fence syncscope("singlethread") acquire 350 ret void 351} 352 353declare void @llvm.memcpy(i8* %dest, i8* %src, i32 %len, i1 %isvolatile) 354declare void @llvm.memset(i8* %dest, i8 %val, i32 %len, i1 %isvolatile) 355 356; TEST 14 - negative, checking volatile intrinsics. 357 358; It is odd to add nocapture but a result of the llvm.memcpy nocapture. 359; 360; IS__TUNIT____: Function Attrs: argmemonly nounwind 361; IS__CGSCC____: Function Attrs: argmemonly nounwind 362; CHECK-NOT: nosync 363define i32 @memcpy_volatile(i8* %ptr1, i8* %ptr2) { 364; CHECK-LABEL: define {{[^@]+}}@memcpy_volatile 365; CHECK-SAME: (i8* nocapture writeonly [[PTR1:%.*]], i8* nocapture readonly [[PTR2:%.*]]) 366; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* noalias nocapture writeonly [[PTR1]], i8* noalias nocapture readonly [[PTR2]], i32 8, i1 true) 367; CHECK-NEXT: ret i32 4 368; 369 call void @llvm.memcpy(i8* %ptr1, i8* %ptr2, i32 8, i1 1) 370 ret i32 4 371} 372 373; TEST 15 - positive, non-volatile intrinsic. 374 375; It is odd to add nocapture but a result of the llvm.memset nocapture. 376; 377; IS__TUNIT____: Function Attrs: argmemonly nosync 378; IS__CGSCC____: Function Attrs: argmemonly nosync 379define i32 @memset_non_volatile(i8* %ptr1, i8 %val) { 380; CHECK-LABEL: define {{[^@]+}}@memset_non_volatile 381; CHECK-SAME: (i8* nocapture writeonly [[PTR1:%.*]], i8 [[VAL:%.*]]) 382; CHECK-NEXT: call void @llvm.memset.p0i8.i32(i8* nocapture writeonly [[PTR1]], i8 [[VAL]], i32 8, i1 false) 383; CHECK-NEXT: ret i32 4 384; 385 call void @llvm.memset(i8* %ptr1, i8 %val, i32 8, i1 0) 386 ret i32 4 387} 388 389; TEST 16 - negative, inline assembly. 390 391define i32 @inline_asm_test(i32 %x) { 392; CHECK-LABEL: define {{[^@]+}}@inline_asm_test 393; CHECK-SAME: (i32 [[X:%.*]]) 394; CHECK-NEXT: [[TMP1:%.*]] = call i32 asm "bswap $0", "=r,r"(i32 [[X]]) 395; CHECK-NEXT: ret i32 4 396; 397 call i32 asm "bswap $0", "=r,r"(i32 %x) 398 ret i32 4 399} 400 401declare void @readnone_test() convergent readnone 402 403; TEST 17 - negative. Convergent 404define void @convergent_readnone(){ 405; CHECK-LABEL: define {{[^@]+}}@convergent_readnone() 406; CHECK-NEXT: call void @readnone_test() 407; CHECK-NEXT: ret void 408; 409 call void @readnone_test() 410 ret void 411} 412 413; CHECK: Function Attrs: nounwind 414; CHECK-NEXT: declare void @llvm.x86.sse2.clflush(i8*) 415declare void @llvm.x86.sse2.clflush(i8*) 416@a = common global i32 0, align 4 417 418; TEST 18 - negative. Synchronizing intrinsic 419 420; IS__TUNIT____: Function Attrs: nounwind 421; IS__CGSCC____: Function Attrs: nounwind 422; CHECK-NOT: nosync 423define void @i_totally_sync() { 424; CHECK-LABEL: define {{[^@]+}}@i_totally_sync() 425; CHECK-NEXT: tail call void @llvm.x86.sse2.clflush(i8* nonnull align 4 dereferenceable(4) bitcast (i32* @a to i8*)) 426; CHECK-NEXT: ret void 427; 428 tail call void @llvm.x86.sse2.clflush(i8* bitcast (i32* @a to i8*)) 429 ret void 430} 431 432declare float @llvm.cos(float %val) readnone 433 434; TEST 19 - positive, readnone & non-convergent intrinsic. 435 436; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn 437; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn 438define i32 @cos_test(float %x) { 439; CHECK-LABEL: define {{[^@]+}}@cos_test 440; CHECK-SAME: (float [[X:%.*]]) 441; CHECK-NEXT: ret i32 4 442; 443 call float @llvm.cos(float %x) 444 ret i32 4 445} 446 447; IS__TUNIT____: Function Attrs: nosync nounwind 448; IS__CGSCC____: Function Attrs: nosync nounwind 449define float @cos_test2(float %x) { 450; CHECK-LABEL: define {{[^@]+}}@cos_test2 451; CHECK-SAME: (float [[X:%.*]]) 452; CHECK-NEXT: [[C:%.*]] = call float @llvm.cos.f32(float [[X]]) 453; CHECK-NEXT: ret float [[C]] 454; 455 %c = call float @llvm.cos(float %x) 456 ret float %c 457} 458