1------------------------------------------------------------------------------ 2-- -- 3-- GNAT COMPILER COMPONENTS -- 4-- -- 5-- E X P _ C O D E -- 6-- -- 7-- B o d y -- 8-- -- 9-- Copyright (C) 1996-2018, Free Software Foundation, Inc. -- 10-- -- 11-- GNAT is free software; you can redistribute it and/or modify it under -- 12-- terms of the GNU General Public License as published by the Free Soft- -- 13-- ware Foundation; either version 3, or (at your option) any later ver- -- 14-- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- 15-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- 16-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- 17-- for more details. You should have received a copy of the GNU General -- 18-- Public License distributed with GNAT; see file COPYING3. If not, go to -- 19-- http://www.gnu.org/licenses for a complete copy of the license. -- 20-- -- 21-- GNAT was originally developed by the GNAT team at New York University. -- 22-- Extensive contributions were provided by Ada Core Technologies Inc. -- 23-- -- 24------------------------------------------------------------------------------ 25 26with Atree; use Atree; 27with Einfo; use Einfo; 28with Errout; use Errout; 29with Lib; use Lib; 30with Namet; use Namet; 31with Nlists; use Nlists; 32with Nmake; use Nmake; 33with Opt; use Opt; 34with Rtsfind; use Rtsfind; 35with Sem_Aux; use Sem_Aux; 36with Sem_Eval; use Sem_Eval; 37with Sem_Util; use Sem_Util; 38with Sem_Warn; use Sem_Warn; 39with Sinfo; use Sinfo; 40with Stringt; use Stringt; 41with Tbuild; use Tbuild; 42 43package body Exp_Code is 44 45 ----------------------- 46 -- Local_Subprograms -- 47 ----------------------- 48 49 function Asm_Constraint (Operand_Var : Node_Id) return Node_Id; 50 -- Common processing for Asm_Input_Constraint and Asm_Output_Constraint. 51 -- Obtains the constraint argument from the global operand variable 52 -- Operand_Var, which must be non-Empty. 53 54 function Asm_Operand (Operand_Var : Node_Id) return Node_Id; 55 -- Common processing for Asm_Input_Value and Asm_Output_Variable. Obtains 56 -- the value/variable argument from Operand_Var, the global operand 57 -- variable. Returns Empty if no operand available. 58 59 function Get_String_Node (S : Node_Id) return Node_Id; 60 -- Given S, a static expression node of type String, returns the 61 -- string literal node. This is needed to deal with the use of constants 62 -- for these expressions, which is perfectly permissible. 63 64 procedure Next_Asm_Operand (Operand_Var : in out Node_Id); 65 -- Common processing for Next_Asm_Input and Next_Asm_Output, updates 66 -- the value of the global operand variable Operand_Var appropriately. 67 68 procedure Setup_Asm_IO_Args (Arg : Node_Id; Operand_Var : out Node_Id); 69 -- Common processing for Setup_Asm_Inputs and Setup_Asm_Outputs. Arg 70 -- is the actual parameter from the call, and Operand_Var is the global 71 -- operand variable to be initialized to the first operand. 72 73 ---------------------- 74 -- Global Variables -- 75 ---------------------- 76 77 Current_Input_Operand : Node_Id := Empty; 78 -- Points to current Asm_Input_Operand attribute reference. Initialized 79 -- by Setup_Asm_Inputs, updated by Next_Asm_Input, and referenced by 80 -- Asm_Input_Constraint and Asm_Input_Value. 81 82 Current_Output_Operand : Node_Id := Empty; 83 -- Points to current Asm_Output_Operand attribute reference. Initialized 84 -- by Setup_Asm_Outputs, updated by Next_Asm_Output, and referenced by 85 -- Asm_Output_Constraint and Asm_Output_Variable. 86 87 -------------------- 88 -- Asm_Constraint -- 89 -------------------- 90 91 function Asm_Constraint (Operand_Var : Node_Id) return Node_Id is 92 begin 93 pragma Assert (Present (Operand_Var)); 94 return Get_String_Node (First (Expressions (Operand_Var))); 95 end Asm_Constraint; 96 97 -------------------------- 98 -- Asm_Input_Constraint -- 99 -------------------------- 100 101 -- Note: error checking on Asm_Input attribute done in Sem_Attr 102 103 function Asm_Input_Constraint return Node_Id is 104 begin 105 return Get_String_Node (Asm_Constraint (Current_Input_Operand)); 106 end Asm_Input_Constraint; 107 108 --------------------- 109 -- Asm_Input_Value -- 110 --------------------- 111 112 -- Note: error checking on Asm_Input attribute done in Sem_Attr 113 114 function Asm_Input_Value return Node_Id is 115 begin 116 return Asm_Operand (Current_Input_Operand); 117 end Asm_Input_Value; 118 119 ----------------- 120 -- Asm_Operand -- 121 ----------------- 122 123 function Asm_Operand (Operand_Var : Node_Id) return Node_Id is 124 begin 125 if No (Operand_Var) then 126 return Empty; 127 elsif Error_Posted (Operand_Var) then 128 return Error; 129 else 130 return Next (First (Expressions (Operand_Var))); 131 end if; 132 end Asm_Operand; 133 134 --------------------------- 135 -- Asm_Output_Constraint -- 136 --------------------------- 137 138 -- Note: error checking on Asm_Output attribute done in Sem_Attr 139 140 function Asm_Output_Constraint return Node_Id is 141 begin 142 return Asm_Constraint (Current_Output_Operand); 143 end Asm_Output_Constraint; 144 145 ------------------------- 146 -- Asm_Output_Variable -- 147 ------------------------- 148 149 -- Note: error checking on Asm_Output attribute done in Sem_Attr 150 151 function Asm_Output_Variable return Node_Id is 152 begin 153 return Asm_Operand (Current_Output_Operand); 154 end Asm_Output_Variable; 155 156 ------------------ 157 -- Asm_Template -- 158 ------------------ 159 160 function Asm_Template (N : Node_Id) return Node_Id is 161 Call : constant Node_Id := Expression (Expression (N)); 162 Temp : constant Node_Id := First_Actual (Call); 163 164 begin 165 -- Require static expression for template. We also allow a string 166 -- literal (this is useful for Ada 83 mode where string expressions 167 -- are never static). 168 169 if Is_OK_Static_Expression (Temp) 170 or else (Ada_Version = Ada_83 171 and then Nkind (Temp) = N_String_Literal) 172 then 173 return Get_String_Node (Temp); 174 175 else 176 Flag_Non_Static_Expr ("asm template argument is not static!", Temp); 177 return Empty; 178 end if; 179 end Asm_Template; 180 181 ---------------------- 182 -- Clobber_Get_Next -- 183 ---------------------- 184 185 Clobber_Node : Node_Id; 186 -- String literal node for clobber string. Initialized by Clobber_Setup, 187 -- and not modified by Clobber_Get_Next. Empty if clobber string was in 188 -- error (resulting in no clobber arguments being returned). 189 190 Clobber_Ptr : Pos; 191 -- Pointer to current character of string. Initialized to 1 by the call 192 -- to Clobber_Setup, and then updated by Clobber_Get_Next. 193 194 function Clobber_Get_Next return Address is 195 Str : constant String_Id := Strval (Clobber_Node); 196 Len : constant Nat := String_Length (Str); 197 C : Character; 198 199 begin 200 if No (Clobber_Node) then 201 return Null_Address; 202 end if; 203 204 -- Skip spaces and commas before next register name 205 206 loop 207 -- Return null string if no more names 208 209 if Clobber_Ptr > Len then 210 return Null_Address; 211 end if; 212 213 C := Get_Character (Get_String_Char (Str, Clobber_Ptr)); 214 exit when C /= ',' and then C /= ' '; 215 Clobber_Ptr := Clobber_Ptr + 1; 216 end loop; 217 218 -- Acquire next register name 219 220 Name_Len := 0; 221 loop 222 Add_Char_To_Name_Buffer (C); 223 Clobber_Ptr := Clobber_Ptr + 1; 224 exit when Clobber_Ptr > Len; 225 C := Get_Character (Get_String_Char (Str, Clobber_Ptr)); 226 exit when C = ',' or else C = ' '; 227 end loop; 228 229 Name_Buffer (Name_Len + 1) := ASCII.NUL; 230 return Name_Buffer'Address; 231 end Clobber_Get_Next; 232 233 ------------------- 234 -- Clobber_Setup -- 235 ------------------- 236 237 procedure Clobber_Setup (N : Node_Id) is 238 Call : constant Node_Id := Expression (Expression (N)); 239 Clob : constant Node_Id := Next_Actual ( 240 Next_Actual ( 241 Next_Actual ( 242 First_Actual (Call)))); 243 begin 244 if not Is_OK_Static_Expression (Clob) then 245 Flag_Non_Static_Expr ("asm clobber argument is not static!", Clob); 246 Clobber_Node := Empty; 247 else 248 Clobber_Node := Get_String_Node (Clob); 249 Clobber_Ptr := 1; 250 end if; 251 end Clobber_Setup; 252 253 --------------------- 254 -- Expand_Asm_Call -- 255 --------------------- 256 257 procedure Expand_Asm_Call (N : Node_Id) is 258 Loc : constant Source_Ptr := Sloc (N); 259 260 procedure Check_IO_Operand (N : Node_Id); 261 -- Check for incorrect input or output operand 262 263 ---------------------- 264 -- Check_IO_Operand -- 265 ---------------------- 266 267 procedure Check_IO_Operand (N : Node_Id) is 268 Err : Node_Id := N; 269 270 begin 271 -- The only identifier allowed is No_xxput_Operands. Since we 272 -- know the type is right, it is sufficient to see if the 273 -- referenced entity is in a runtime routine. 274 275 if Is_Entity_Name (N) 276 and then Is_Predefined_Unit (Get_Source_Unit (Entity (N))) 277 then 278 return; 279 280 -- An attribute reference is fine, again the analysis reasonably 281 -- guarantees that the attribute must be subtype'Asm_??put. 282 283 elsif Nkind (N) = N_Attribute_Reference then 284 return; 285 286 -- The only other allowed form is an array aggregate in which 287 -- all the entries are positional and are attribute references. 288 289 elsif Nkind (N) = N_Aggregate then 290 if Present (Component_Associations (N)) then 291 Err := First (Component_Associations (N)); 292 293 elsif Present (Expressions (N)) then 294 Err := First (Expressions (N)); 295 while Present (Err) loop 296 exit when Nkind (Err) /= N_Attribute_Reference; 297 Next (Err); 298 end loop; 299 300 if No (Err) then 301 return; 302 end if; 303 end if; 304 end if; 305 306 -- If we fall through, Err is pointing to the bad node 307 308 Error_Msg_N ("Asm operand has wrong form", Err); 309 end Check_IO_Operand; 310 311 -- Start of processing for Expand_Asm_Call 312 313 begin 314 -- Check that the input and output operands have the right 315 -- form, as required by the documentation of the Asm feature: 316 317 -- OUTPUT_OPERAND_LIST ::= 318 -- No_Output_Operands 319 -- | OUTPUT_OPERAND_ATTRIBUTE 320 -- | (OUTPUT_OPERAND_ATTRIBUTE @{,OUTPUT_OPERAND_ATTRIBUTE@}) 321 322 -- OUTPUT_OPERAND_ATTRIBUTE ::= 323 -- SUBTYPE_MARK'Asm_Output (static_string_EXPRESSION, NAME) 324 325 -- INPUT_OPERAND_LIST ::= 326 -- No_Input_Operands 327 -- | INPUT_OPERAND_ATTRIBUTE 328 -- | (INPUT_OPERAND_ATTRIBUTE @{,INPUT_OPERAND_ATTRIBUTE@}) 329 330 -- INPUT_OPERAND_ATTRIBUTE ::= 331 -- SUBTYPE_MARK'Asm_Input (static_string_EXPRESSION, EXPRESSION) 332 333 declare 334 Arg_Output : constant Node_Id := Next_Actual (First_Actual (N)); 335 Arg_Input : constant Node_Id := Next_Actual (Arg_Output); 336 begin 337 Check_IO_Operand (Arg_Output); 338 Check_IO_Operand (Arg_Input); 339 end; 340 341 -- If we have the function call case, we are inside a code statement, 342 -- and the tree is already in the necessary form for gigi. 343 344 if Nkind (N) = N_Function_Call then 345 null; 346 347 -- For the procedure case, we convert the call into a code statement 348 349 else 350 pragma Assert (Nkind (N) = N_Procedure_Call_Statement); 351 352 -- Note: strictly we should change the procedure call to a function 353 -- call in the qualified expression, but since we are not going to 354 -- reanalyze (see below), and the interface subprograms in this 355 -- package don't care, we can leave it as a procedure call. 356 357 Rewrite (N, 358 Make_Code_Statement (Loc, 359 Expression => 360 Make_Qualified_Expression (Loc, 361 Subtype_Mark => New_Occurrence_Of (RTE (RE_Asm_Insn), Loc), 362 Expression => Relocate_Node (N)))); 363 364 -- There is no need to reanalyze this node, it is completely analyzed 365 -- already, at least sufficiently for the purposes of the abstract 366 -- procedural interface defined in this package. Furthermore if we 367 -- let it go through the normal analysis, that would include some 368 -- inappropriate checks that apply only to explicit code statements 369 -- in the source, and not to calls to intrinsics. 370 371 Set_Analyzed (N); 372 Check_Code_Statement (N); 373 end if; 374 end Expand_Asm_Call; 375 376 --------------------- 377 -- Get_String_Node -- 378 --------------------- 379 380 function Get_String_Node (S : Node_Id) return Node_Id is 381 begin 382 if Nkind (S) = N_String_Literal then 383 return S; 384 else 385 pragma Assert (Ekind (Entity (S)) = E_Constant); 386 return Get_String_Node (Constant_Value (Entity (S))); 387 end if; 388 end Get_String_Node; 389 390 --------------------- 391 -- Is_Asm_Volatile -- 392 --------------------- 393 394 function Is_Asm_Volatile (N : Node_Id) return Boolean is 395 Call : constant Node_Id := Expression (Expression (N)); 396 Vol : constant Node_Id := 397 Next_Actual ( 398 Next_Actual ( 399 Next_Actual ( 400 Next_Actual ( 401 First_Actual (Call))))); 402 begin 403 if not Is_OK_Static_Expression (Vol) then 404 Flag_Non_Static_Expr ("asm volatile argument is not static!", Vol); 405 return False; 406 else 407 return Is_True (Expr_Value (Vol)); 408 end if; 409 end Is_Asm_Volatile; 410 411 -------------------- 412 -- Next_Asm_Input -- 413 -------------------- 414 415 procedure Next_Asm_Input is 416 begin 417 Next_Asm_Operand (Current_Input_Operand); 418 end Next_Asm_Input; 419 420 ---------------------- 421 -- Next_Asm_Operand -- 422 ---------------------- 423 424 procedure Next_Asm_Operand (Operand_Var : in out Node_Id) is 425 begin 426 pragma Assert (Present (Operand_Var)); 427 428 if Nkind (Parent (Operand_Var)) = N_Aggregate then 429 Operand_Var := Next (Operand_Var); 430 else 431 Operand_Var := Empty; 432 end if; 433 end Next_Asm_Operand; 434 435 --------------------- 436 -- Next_Asm_Output -- 437 --------------------- 438 439 procedure Next_Asm_Output is 440 begin 441 Next_Asm_Operand (Current_Output_Operand); 442 end Next_Asm_Output; 443 444 ---------------------- 445 -- Setup_Asm_Inputs -- 446 ---------------------- 447 448 procedure Setup_Asm_Inputs (N : Node_Id) is 449 Call : constant Node_Id := Expression (Expression (N)); 450 begin 451 Setup_Asm_IO_Args 452 (Next_Actual (Next_Actual (First_Actual (Call))), 453 Current_Input_Operand); 454 end Setup_Asm_Inputs; 455 456 ----------------------- 457 -- Setup_Asm_IO_Args -- 458 ----------------------- 459 460 procedure Setup_Asm_IO_Args (Arg : Node_Id; Operand_Var : out Node_Id) is 461 begin 462 -- Case of single argument 463 464 if Nkind (Arg) = N_Attribute_Reference then 465 Operand_Var := Arg; 466 467 -- Case of list of arguments 468 469 elsif Nkind (Arg) = N_Aggregate then 470 if Expressions (Arg) = No_List then 471 Operand_Var := Empty; 472 else 473 Operand_Var := First (Expressions (Arg)); 474 end if; 475 476 -- Otherwise must be default (no operands) case 477 478 else 479 Operand_Var := Empty; 480 end if; 481 end Setup_Asm_IO_Args; 482 483 ----------------------- 484 -- Setup_Asm_Outputs -- 485 ----------------------- 486 487 procedure Setup_Asm_Outputs (N : Node_Id) is 488 Call : constant Node_Id := Expression (Expression (N)); 489 begin 490 Setup_Asm_IO_Args 491 (Next_Actual (First_Actual (Call)), 492 Current_Output_Operand); 493 end Setup_Asm_Outputs; 494 495end Exp_Code; 496