1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2; RUN: llc -mtriple=riscv32 -verify-machineinstrs -no-integrated-as < %s \ 3; RUN: | FileCheck -check-prefix=RV32I %s 4; RUN: llc -mtriple=riscv64 -verify-machineinstrs -no-integrated-as < %s \ 5; RUN: | FileCheck -check-prefix=RV64I %s 6 7@gi = external global i32 8 9define i32 @constraint_r(i32 %a) nounwind { 10; RV32I-LABEL: constraint_r: 11; RV32I: # %bb.0: 12; RV32I-NEXT: lui a1, %hi(gi) 13; RV32I-NEXT: lw a1, %lo(gi)(a1) 14; RV32I-NEXT: #APP 15; RV32I-NEXT: add a0, a0, a1 16; RV32I-NEXT: #NO_APP 17; RV32I-NEXT: ret 18; 19; RV64I-LABEL: constraint_r: 20; RV64I: # %bb.0: 21; RV64I-NEXT: lui a1, %hi(gi) 22; RV64I-NEXT: lw a1, %lo(gi)(a1) 23; RV64I-NEXT: #APP 24; RV64I-NEXT: add a0, a0, a1 25; RV64I-NEXT: #NO_APP 26; RV64I-NEXT: ret 27 %1 = load i32, ptr @gi 28 %2 = tail call i32 asm "add $0, $1, $2", "=r,r,r"(i32 %a, i32 %1) 29 ret i32 %2 30} 31 32; Don't allow 'x0' for 'r'. Some instructions have a different behavior when 33; x0 is encoded. 34define i32 @constraint_r_zero(i32 %a) nounwind { 35; RV32I-LABEL: constraint_r_zero: 36; RV32I: # %bb.0: 37; RV32I-NEXT: lui a0, %hi(gi) 38; RV32I-NEXT: lw a0, %lo(gi)(a0) 39; RV32I-NEXT: li a1, 0 40; RV32I-NEXT: #APP 41; RV32I-NEXT: add a0, a1, a0 42; RV32I-NEXT: #NO_APP 43; RV32I-NEXT: ret 44; 45; RV64I-LABEL: constraint_r_zero: 46; RV64I: # %bb.0: 47; RV64I-NEXT: lui a0, %hi(gi) 48; RV64I-NEXT: lw a0, %lo(gi)(a0) 49; RV64I-NEXT: li a1, 0 50; RV64I-NEXT: #APP 51; RV64I-NEXT: add a0, a1, a0 52; RV64I-NEXT: #NO_APP 53; RV64I-NEXT: ret 54 %1 = load i32, ptr @gi 55 %2 = tail call i32 asm "add $0, $1, $2", "=r,r,r"(i32 0, i32 %1) 56 ret i32 %2 57} 58 59define i32 @constraint_cr(i32 %a) nounwind { 60; RV32I-LABEL: constraint_cr: 61; RV32I: # %bb.0: 62; RV32I-NEXT: lui a1, %hi(gi) 63; RV32I-NEXT: lw a1, %lo(gi)(a1) 64; RV32I-NEXT: #APP 65; RV32I-NEXT: c.add a0, a0, a1 66; RV32I-NEXT: #NO_APP 67; RV32I-NEXT: ret 68; 69; RV64I-LABEL: constraint_cr: 70; RV64I: # %bb.0: 71; RV64I-NEXT: lui a1, %hi(gi) 72; RV64I-NEXT: lw a1, %lo(gi)(a1) 73; RV64I-NEXT: #APP 74; RV64I-NEXT: c.add a0, a0, a1 75; RV64I-NEXT: #NO_APP 76; RV64I-NEXT: ret 77 %1 = load i32, ptr @gi 78 %2 = tail call i32 asm "c.add $0, $1, $2", "=^cr,0,^cr"(i32 %a, i32 %1) 79 ret i32 %2 80} 81 82define i32 @constraint_i(i32 %a) nounwind { 83; RV32I-LABEL: constraint_i: 84; RV32I: # %bb.0: 85; RV32I-NEXT: #APP 86; RV32I-NEXT: addi a0, a0, 113 87; RV32I-NEXT: #NO_APP 88; RV32I-NEXT: ret 89; 90; RV64I-LABEL: constraint_i: 91; RV64I: # %bb.0: 92; RV64I-NEXT: #APP 93; RV64I-NEXT: addi a0, a0, 113 94; RV64I-NEXT: #NO_APP 95; RV64I-NEXT: ret 96 %1 = load i32, ptr @gi 97 %2 = tail call i32 asm "addi $0, $1, $2", "=r,r,i"(i32 %a, i32 113) 98 ret i32 %2 99} 100 101define void @constraint_I() nounwind { 102; RV32I-LABEL: constraint_I: 103; RV32I: # %bb.0: 104; RV32I-NEXT: #APP 105; RV32I-NEXT: addi a0, a0, 2047 106; RV32I-NEXT: #NO_APP 107; RV32I-NEXT: #APP 108; RV32I-NEXT: addi a0, a0, -2048 109; RV32I-NEXT: #NO_APP 110; RV32I-NEXT: ret 111; 112; RV64I-LABEL: constraint_I: 113; RV64I: # %bb.0: 114; RV64I-NEXT: #APP 115; RV64I-NEXT: addi a0, a0, 2047 116; RV64I-NEXT: #NO_APP 117; RV64I-NEXT: #APP 118; RV64I-NEXT: addi a0, a0, -2048 119; RV64I-NEXT: #NO_APP 120; RV64I-NEXT: ret 121 tail call void asm sideeffect "addi a0, a0, $0", "I"(i32 2047) 122 tail call void asm sideeffect "addi a0, a0, $0", "I"(i32 -2048) 123 ret void 124} 125 126define void @constraint_J() nounwind { 127; RV32I-LABEL: constraint_J: 128; RV32I: # %bb.0: 129; RV32I-NEXT: #APP 130; RV32I-NEXT: addi a0, a0, 0 131; RV32I-NEXT: #NO_APP 132; RV32I-NEXT: ret 133; 134; RV64I-LABEL: constraint_J: 135; RV64I: # %bb.0: 136; RV64I-NEXT: #APP 137; RV64I-NEXT: addi a0, a0, 0 138; RV64I-NEXT: #NO_APP 139; RV64I-NEXT: ret 140 tail call void asm sideeffect "addi a0, a0, $0", "J"(i32 0) 141 ret void 142} 143 144define void @constraint_K() nounwind { 145; RV32I-LABEL: constraint_K: 146; RV32I: # %bb.0: 147; RV32I-NEXT: #APP 148; RV32I-NEXT: csrwi mstatus, 31 149; RV32I-NEXT: #NO_APP 150; RV32I-NEXT: #APP 151; RV32I-NEXT: csrwi mstatus, 0 152; RV32I-NEXT: #NO_APP 153; RV32I-NEXT: ret 154; 155; RV64I-LABEL: constraint_K: 156; RV64I: # %bb.0: 157; RV64I-NEXT: #APP 158; RV64I-NEXT: csrwi mstatus, 31 159; RV64I-NEXT: #NO_APP 160; RV64I-NEXT: #APP 161; RV64I-NEXT: csrwi mstatus, 0 162; RV64I-NEXT: #NO_APP 163; RV64I-NEXT: ret 164 tail call void asm sideeffect "csrwi mstatus, $0", "K"(i32 31) 165 tail call void asm sideeffect "csrwi mstatus, $0", "K"(i32 0) 166 ret void 167} 168 169define i32 @modifier_z_zero(i32 %a) nounwind { 170; RV32I-LABEL: modifier_z_zero: 171; RV32I: # %bb.0: 172; RV32I-NEXT: #APP 173; RV32I-NEXT: add a0, a0, zero 174; RV32I-NEXT: #NO_APP 175; RV32I-NEXT: ret 176; 177; RV64I-LABEL: modifier_z_zero: 178; RV64I: # %bb.0: 179; RV64I-NEXT: #APP 180; RV64I-NEXT: add a0, a0, zero 181; RV64I-NEXT: #NO_APP 182; RV64I-NEXT: ret 183 %1 = tail call i32 asm "add $0, $1, ${2:z}", "=r,r,i"(i32 %a, i32 0) 184 ret i32 %1 185} 186 187define i32 @modifier_z_nonzero(i32 %a) nounwind { 188; RV32I-LABEL: modifier_z_nonzero: 189; RV32I: # %bb.0: 190; RV32I-NEXT: #APP 191; RV32I-NEXT: add a0, a0, 1 192; RV32I-NEXT: #NO_APP 193; RV32I-NEXT: ret 194; 195; RV64I-LABEL: modifier_z_nonzero: 196; RV64I: # %bb.0: 197; RV64I-NEXT: #APP 198; RV64I-NEXT: add a0, a0, 1 199; RV64I-NEXT: #NO_APP 200; RV64I-NEXT: ret 201 %1 = tail call i32 asm "add $0, $1, ${2:z}", "=r,r,i"(i32 %a, i32 1) 202 ret i32 %1 203} 204 205define i32 @modifier_i_imm(i32 %a) nounwind { 206; RV32I-LABEL: modifier_i_imm: 207; RV32I: # %bb.0: 208; RV32I-NEXT: #APP 209; RV32I-NEXT: addi a0, a0, 1 210; RV32I-NEXT: #NO_APP 211; RV32I-NEXT: ret 212; 213; RV64I-LABEL: modifier_i_imm: 214; RV64I: # %bb.0: 215; RV64I-NEXT: #APP 216; RV64I-NEXT: addi a0, a0, 1 217; RV64I-NEXT: #NO_APP 218; RV64I-NEXT: ret 219 %1 = tail call i32 asm "add${2:i} $0, $1, $2", "=r,r,ri"(i32 %a, i32 1) 220 ret i32 %1 221} 222 223define i32 @modifier_i_reg(i32 %a, i32 %b) nounwind { 224; RV32I-LABEL: modifier_i_reg: 225; RV32I: # %bb.0: 226; RV32I-NEXT: #APP 227; RV32I-NEXT: add a0, a0, a1 228; RV32I-NEXT: #NO_APP 229; RV32I-NEXT: ret 230; 231; RV64I-LABEL: modifier_i_reg: 232; RV64I: # %bb.0: 233; RV64I-NEXT: #APP 234; RV64I-NEXT: add a0, a0, a1 235; RV64I-NEXT: #NO_APP 236; RV64I-NEXT: ret 237 %1 = tail call i32 asm "add${2:i} $0, $1, $2", "=r,r,ri"(i32 %a, i32 %b) 238 ret i32 %1 239} 240 241;; `.insn 0x4, 0x33 | (${0:N} << 7) | (${1:N} << 15) | (${2:N} << 20)` is the 242;; raw encoding of `add` 243 244define i32 @modifier_N_reg(i32 %a, i32 %b) nounwind { 245; RV32I-LABEL: modifier_N_reg: 246; RV32I: # %bb.0: 247; RV32I-NEXT: #APP 248; RV32I-NEXT: .insn 0x4, 0x33 | (10 << 7) | (10 << 15) | (11 << 20) 249; RV32I-NEXT: #NO_APP 250; RV32I-NEXT: ret 251; 252; RV64I-LABEL: modifier_N_reg: 253; RV64I: # %bb.0: 254; RV64I-NEXT: #APP 255; RV64I-NEXT: .insn 0x4, 0x33 | (10 << 7) | (10 << 15) | (11 << 20) 256; RV64I-NEXT: #NO_APP 257; RV64I-NEXT: ret 258 %1 = tail call i32 asm ".insn 0x4, 0x33 | (${0:N} << 7) | (${1:N} << 15) | (${2:N} << 20)", "=r,r,r"(i32 %a, i32 %b) 259 ret i32 %1 260} 261 262;; `.insn 0x2, 0x9422 | (${0:N} << 7) | (${2:N} << 2)` is the raw encoding of 263;; `c.add` (note the constraint that the first input should be the same as the 264;; output). 265 266define i32 @modifier_N_with_cr_reg(i32 %a, i32 %b) nounwind { 267; RV32I-LABEL: modifier_N_with_cr_reg: 268; RV32I: # %bb.0: 269; RV32I-NEXT: #APP 270; RV32I-NEXT: .insn 0x2, 0x9422 | (10 << 7) | (11 << 2) 271; RV32I-NEXT: #NO_APP 272; RV32I-NEXT: ret 273; 274; RV64I-LABEL: modifier_N_with_cr_reg: 275; RV64I: # %bb.0: 276; RV64I-NEXT: #APP 277; RV64I-NEXT: .insn 0x2, 0x9422 | (10 << 7) | (11 << 2) 278; RV64I-NEXT: #NO_APP 279; RV64I-NEXT: ret 280 %1 = tail call i32 asm ".insn 0x2, 0x9422 | (${0:N} << 7) | (${2:N} << 2)", "=^cr,0,^cr"(i32 %a, i32 %b) 281 ret i32 %1 282} 283 284define void @operand_global() nounwind { 285; RV32I-LABEL: operand_global: 286; RV32I: # %bb.0: 287; RV32I-NEXT: #APP 288; RV32I-NEXT: .8byte gi 289; RV32I-NEXT: #NO_APP 290; RV32I-NEXT: ret 291; 292; RV64I-LABEL: operand_global: 293; RV64I: # %bb.0: 294; RV64I-NEXT: #APP 295; RV64I-NEXT: .8byte gi 296; RV64I-NEXT: #NO_APP 297; RV64I-NEXT: ret 298 tail call void asm sideeffect ".8byte $0", "i"(ptr @gi) 299 ret void 300} 301 302define void @operand_block_address() nounwind { 303; RV32I-LABEL: operand_block_address: 304; RV32I: # %bb.0: 305; RV32I-NEXT: #APP 306; RV32I-NEXT: j .Ltmp0 307; RV32I-NEXT: #NO_APP 308; RV32I-NEXT: .Ltmp0: # Block address taken 309; RV32I-NEXT: # %bb.1: # %bb 310; RV32I-NEXT: ret 311; 312; RV64I-LABEL: operand_block_address: 313; RV64I: # %bb.0: 314; RV64I-NEXT: #APP 315; RV64I-NEXT: j .Ltmp0 316; RV64I-NEXT: #NO_APP 317; RV64I-NEXT: .Ltmp0: # Block address taken 318; RV64I-NEXT: # %bb.1: # %bb 319; RV64I-NEXT: ret 320 call void asm sideeffect "j $0", "i"(ptr blockaddress(@operand_block_address, %bb)) 321 br label %bb 322bb: 323 ret void 324} 325 326; TODO: expand tests for more complex constraints, out of range immediates etc 327