< prev index next >

src/java.base/share/classes/jdk/internal/foreign/abi/x64/sysv/CallingSequenceBuilderImpl.java

Print this page




   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 package jdk.internal.foreign.abi.x64.sysv;
  24 
  25 import java.foreign.NativeMethodType;
  26 import java.foreign.NativeTypes;
  27 import java.foreign.layout.Address;
  28 import java.foreign.layout.Group;
  29 import java.foreign.layout.Group.Kind;
  30 import java.foreign.layout.Layout;
  31 import java.foreign.layout.Padding;
  32 import java.foreign.layout.Sequence;
  33 import java.foreign.layout.Value;
  34 import java.foreign.memory.LayoutType;
  35 import java.util.ArrayList;
  36 import java.util.stream.Stream;


  37 import jdk.internal.foreign.Util;
  38 import jdk.internal.foreign.abi.Argument;
  39 import jdk.internal.foreign.abi.ArgumentBinding;
  40 import jdk.internal.foreign.abi.CallingSequence;
  41 import jdk.internal.foreign.abi.Storage;
  42 import jdk.internal.foreign.abi.StorageClass;
  43 import jdk.internal.foreign.abi.x64.CallingSequenceBuilder;
  44 import jdk.internal.foreign.abi.x64.ArgumentClass;
  45 import jdk.internal.foreign.abi.x64.SharedConstants;
  46 
  47 import static sun.security.action.GetBooleanAction.privilegedGetProperty;
  48 
  49 public class StandardCall extends CallingSequenceBuilder {
  50     private static final String[] INTEGER_ARGUMENT_REGISTER_NAMES = { "rdi", "rsi", "rdx", "rcx", "r8", "r9" };
  51     private static final String[] INTEGER_RETURN_REGISTERS_NAMES = { "rax", "rdx" };
  52     private static final String[] X87_RETURN_REGISTERS_NAMES = { "st0", "st1" };





  53 
  54     private static final boolean DEBUG =
  55         privilegedGetProperty("jdk.internal.foreign.abi.x64.sysv.DEBUG");
  56 
  57     // The AVX 512 enlightened ABI says "eight eightbytes"
  58     // Although AMD64 0.99.6 states 4 eightbytes
  59     private static final int MAX_AGGREGATE_REGS_SIZE = 8;
  60 
  61     private static final ArrayList<ArgumentClass> COMPLEX_X87_CLASSES;
  62     private static final SysVx64ABI abi = SysVx64ABI.getInstance();
  63 
  64     static {
  65         COMPLEX_X87_CLASSES = new ArrayList<>();
  66         COMPLEX_X87_CLASSES.add(ArgumentClass.X87);
  67         COMPLEX_X87_CLASSES.add(ArgumentClass.X87UP);
  68         COMPLEX_X87_CLASSES.add(ArgumentClass.X87);
  69         COMPLEX_X87_CLASSES.add(ArgumentClass.X87UP);
  70     }
  71 
  72     public StandardCall() {
  73         super(INTEGER_ARGUMENT_REGISTER_NAMES, INTEGER_RETURN_REGISTERS_NAMES, X87_RETURN_REGISTERS_NAMES,
  74                 Constants.MAX_VECTOR_ARGUMENT_REGISTERS, Constants.MAX_VECTOR_RETURN_REGISTERS);
  75     }
  76 
  77     static class ArgumentInfo {
  78         private final ArrayList<ArgumentClass> classes;
  79         private final int nIntegerRegs, nVectorRegs, nX87Regs;
  80         private final boolean inMemory;
  81 
  82         public ArgumentInfo(ArrayList<ArgumentClass> classes, int nIntegerRegs, int nVectorRegs, int nX87Regs) {
  83             this.classes = classes;
  84 
  85             this.nIntegerRegs = nIntegerRegs;
  86             this.nVectorRegs = nVectorRegs;
  87             this.nX87Regs = nX87Regs;
  88 
  89             this.inMemory = false;
  90         }
  91 
  92         public ArgumentInfo(int n) {
  93             this.classes = new ArrayList<>();
  94             for (int i = 0; i < n; i++) {
  95                 classes.add(ArgumentClass.MEMORY);
  96             }
  97 
  98             this.inMemory = true;
  99             this.nIntegerRegs = 0;
 100             this.nVectorRegs = 0;
 101             this.nX87Regs = 0;


 102         }
 103 
 104         public int getIntegerRegs() {
 105             return nIntegerRegs;


 106         }
 107 
 108         public int getVectorRegs() {
 109             return nVectorRegs;


 110         }
 111 
 112         public int getX87Regs() {
 113             return nX87Regs;

 114         }
 115 
 116         public boolean inMemory() {
 117             return inMemory;


 118         }
 119 
 120         public ArrayList<ArgumentClass> getClasses() {
 121             return classes;
 122         }
 123 
 124         static ArgumentInfo EMPTY = new ArgumentInfo(new ArrayList<>(), 0, 0, 0);
 125     }
 126 
 127     private ArrayList<ArgumentClass> classifyValueType(Value type) {
 128         ArrayList<ArgumentClass> classes = new ArrayList<>();
 129 
 130         switch (type.kind()) {
 131             case INTEGRAL_SIGNED: case INTEGRAL_UNSIGNED:
 132                 classes.add(ArgumentClass.INTEGER);
 133                 // int128
 134                 long left = (type.bitsSize() / 8) - 8;
 135                 while (left > 0) {
 136                     classes.add(ArgumentClass.INTEGER);
 137                     left -= 8;
 138                 }
 139                 return classes;
 140             case FLOATING_POINT:
 141                 if ((type.bitsSize() / 8) > 8) {
 142                     classes.add(ArgumentClass.X87);
 143                     classes.add(ArgumentClass.X87UP);
 144                     return classes;
 145                 } else {
 146                     classes.add(ArgumentClass.SSE);
 147                     return classes;
 148                 }
 149             default:
 150                 throw new IllegalArgumentException("Type " + type + " is not yet supported");
 151         }
 152     }
 153 
 154     private ArrayList<ArgumentClass> classifyArrayType(Sequence type) {
 155         long nWords = Util.alignUp((type.bitsSize() / 8), 8) / 8;
 156         if (nWords > MAX_AGGREGATE_REGS_SIZE) {
 157             return createMemoryClassArray(nWords);
 158         }
 159 
 160         ArrayList<ArgumentClass> classes = new ArrayList<>();
 161 
 162         for (long i = 0; i < nWords; i++) {
 163             classes.add(ArgumentClass.NO_CLASS);
 164         }
 165 
 166         long offset = 0;
 167         final long count = type.elementsSize();
 168         for (long idx = 0; idx < count; idx++) {
 169             Layout t = type.element();
 170             offset = align(t, false, offset);
 171             ArrayList<ArgumentClass> subclasses = classifyType(t);
 172             if (subclasses.isEmpty()) {
 173                 return classes;
 174             }
 175 
 176             for (int i = 0; i < subclasses.size(); i++) {
 177                 int pos = (int)(offset / 8);
 178                 ArgumentClass newClass = classes.get(i + pos).merge(subclasses.get(i));
 179                 classes.set(i + pos, newClass);
 180             }
 181 
 182             offset += t.bitsSize() / 8;
 183         }
 184 
 185         for (int i = 0; i < classes.size(); i++) {
 186             ArgumentClass c = classes.get(i);
 187 
 188             if (c == ArgumentClass.MEMORY) {
 189                 return createMemoryClassArray(classes.size());
 190             }
 191 


 200             }
 201         }
 202 
 203         if (classes.size() > 2) {
 204             if (classes.get(0) != ArgumentClass.SSE) {
 205                 return createMemoryClassArray(classes.size());
 206             }
 207 
 208             for (int i = 1; i < classes.size(); i++) {
 209                 if (classes.get(i) != ArgumentClass.SSEUP) {
 210                     return createMemoryClassArray(classes.size());
 211                 }
 212             }
 213         }
 214 
 215         return classes;
 216     }
 217 
 218     // TODO: handle zero length arrays
 219     // TODO: Handle nested structs (and primitives)
 220     private ArrayList<ArgumentClass> classifyStructType(Group type) {
 221         long nWords = Util.alignUp((type.bitsSize() / 8), 8) / 8;
 222         if (nWords > MAX_AGGREGATE_REGS_SIZE) {
 223             return createMemoryClassArray(nWords);
 224         }
 225 
 226         ArrayList<ArgumentClass> classes = new ArrayList<>();
 227 
 228         for (long i = 0; i < nWords; i++) {
 229             classes.add(ArgumentClass.NO_CLASS);
 230         }
 231 
 232         long offset = 0;
 233         final int count = type.elements().size();
 234         for (int idx = 0; idx < count; idx++) {
 235             Layout t = type.elements().get(idx);
 236             if (t instanceof Padding) {
 237                 continue;
 238             }
 239             // ignore zero-length array for now
 240             // TODO: handle zero length arrays here
 241             if (t instanceof Sequence) {
 242                 if (((Sequence) t).elementsSize() == 0) {
 243                     continue;
 244                 }
 245             }
 246             offset = align(t, false, offset);
 247             ArrayList<ArgumentClass> subclasses = classifyType(t);
 248             if (subclasses.isEmpty()) {
 249                 return classes;
 250             }
 251 
 252             for (int i = 0; i < subclasses.size(); i++) {
 253                 int pos = (int)(offset / 8);
 254                 ArgumentClass newClass = classes.get(i + pos).merge(subclasses.get(i));
 255                 classes.set(i + pos, newClass);
 256             }
 257 
 258             // TODO: validate union strategy is sound
 259             if (type.kind() != Kind.UNION) {
 260                 offset += t.bitsSize() / 8;
 261             }
 262         }
 263 
 264         for (int i = 0; i < classes.size(); i++) {
 265             ArgumentClass c = classes.get(i);
 266 
 267             if (c == ArgumentClass.MEMORY) {


 277                     return createMemoryClassArray(classes.size());
 278                 }
 279             }
 280         }
 281 
 282         if (classes.size() > 2) {
 283             if (classes.get(0) != ArgumentClass.SSE) {
 284                 return createMemoryClassArray(classes.size());
 285             }
 286 
 287             for (int i = 1; i < classes.size(); i++) {
 288                 if (classes.get(i) != ArgumentClass.SSEUP) {
 289                     return createMemoryClassArray(classes.size());
 290                 }
 291             }
 292         }
 293 
 294         return classes;
 295     }
 296 
 297     private ArrayList<ArgumentClass> classifyType(Layout type) {
 298         try {
 299             if (type instanceof Value) {
 300                 return classifyValueType((Value) type);
 301             } else if (type instanceof Address) {
 302                 ArrayList<ArgumentClass> classes = new ArrayList<>();
 303                 classes.add(ArgumentClass.INTEGER);
 304                 return classes;
 305             } else if (type instanceof Sequence) {
 306                 return classifyArrayType((Sequence) type);
 307             } else if (type instanceof Group) {
 308                 return type.name().isPresent() && type.name().get().equals("LongDoubleComplex") ?
 309                         COMPLEX_X87_CLASSES :
 310                         classifyStructType((Group) type);
 311             } else {
 312                 throw new IllegalArgumentException("Unhandled type " + type);
 313             }
 314         } catch (UnsupportedOperationException e) {
 315             System.err.println("Failed to classify layout: " + type);
 316             throw e;
 317         }
 318     }
 319 
 320     private ArrayList<ArgumentClass> createMemoryClassArray(long n) {
 321         ArrayList<ArgumentClass> classes = new ArrayList<>();
 322         for (int i = 0; i < n; i++) {
 323             classes.add(ArgumentClass.MEMORY);
 324         }
 325 
 326         return classes;
 327     }
 328 
 329     private ArgumentInfo examineArgument(boolean forArguments, Layout type) {
 330         ArrayList<ArgumentClass> classes = classifyType(type);
 331         if (classes.isEmpty()) {
 332             return ArgumentInfo.EMPTY;
 333         }
 334 
 335         int nIntegerRegs = 0;
 336         int nVectorRegs = 0;
 337         int nX87Regs = 0;
 338 
 339         for (ArgumentClass c : classes) {
 340             switch (c) {
 341             case INTEGER:
 342                 nIntegerRegs++;
 343                 break;
 344             case SSE:
 345                 nVectorRegs++;
 346                 break;
 347             case X87:
 348             case X87UP:
 349                 if (forArguments) {
 350                     return new ArgumentInfo(classes.size());
 351                 } else {
 352                     nX87Regs++;
 353                     break;
 354                 }
 355             default:
 356                 break;
 357             }
 358         }
 359 
 360         if (nIntegerRegs != 0 || nVectorRegs != 0 || nX87Regs != 0) {
 361             return new ArgumentInfo(classes, nIntegerRegs, nVectorRegs, nX87Regs);
 362         } else {
 363             return new ArgumentInfo(classes.size());
 364         }
 365     }
 366 
 367     class StorageCalculator {
 368         private final ArrayList<ArgumentBinding>[] bindings;
 369         private final boolean forArguments;
 370 
 371         private int nIntegerRegs = 0;
 372         private int nVectorRegs = 0;
 373         private int nX87Regs = 0;
 374         private long stackOffset = 0;
 375 
 376         StorageCalculator(ArrayList<ArgumentBinding>[] bindings, boolean forArguments) {
 377             this.bindings = bindings;
 378             this.forArguments = forArguments;
 379         }
 380 
 381         void addBindings(Argument arg, ArgumentInfo info) {

 382             if (info.inMemory() ||
 383                     nIntegerRegs + info.getIntegerRegs() > (forArguments ? Constants.MAX_INTEGER_ARGUMENT_REGISTERS : Constants.MAX_INTEGER_RETURN_REGISTERS) ||
 384                     nVectorRegs + info.getVectorRegs() > (forArguments ? Constants.MAX_VECTOR_ARGUMENT_REGISTERS : Constants.MAX_VECTOR_RETURN_REGISTERS)) {
 385                 // stack
 386 
 387                 long alignment = Math.max(alignment(arg.getType(), true), 8);
 388 
 389                 long newStackOffset = Util.alignUp(stackOffset, alignment);
 390 
 391                 // fill holes on stack with nulls
 392                 for (int i = 0; i < (newStackOffset - stackOffset) / 8; i++) {
 393                     bindings[StorageClass.STACK_ARGUMENT_SLOT.ordinal()].add(null);
 394                 }
 395                 stackOffset = newStackOffset;
 396 
 397                 long tmpStackOffset = stackOffset;
 398                 for (int i = 0; i < info.getClasses().size(); i++) {
 399                     Storage storage = new Storage(StorageClass.STACK_ARGUMENT_SLOT, tmpStackOffset / 8, 8);
 400                     bindings[StorageClass.STACK_ARGUMENT_SLOT.ordinal()].add(new ArgumentBinding(storage, arg, i * 8));
 401 
 402                     if (DEBUG) {
 403                         System.out.println("Argument " + arg.getName() + " will be passed on stack at offset " + tmpStackOffset);
 404                     }
 405 
 406                     tmpStackOffset += 8;
 407                 }
 408 
 409                 stackOffset += arg.getType().bitsSize() / 8;
 410             } else {
 411                 // regs
 412                 for (int i = 0; i < info.getClasses().size(); i++) {
 413                     Storage storage;
 414 
 415                     ArgumentClass c = info.getClasses().get(i);
 416 
 417                     switch (c) {
 418                     case INTEGER:
 419                         storage = new Storage(forArguments ? StorageClass.INTEGER_ARGUMENT_REGISTER : StorageClass.INTEGER_RETURN_REGISTER, nIntegerRegs++, SharedConstants.INTEGER_REGISTER_SIZE);
 420                         bindings[storage.getStorageClass().ordinal()].add(new ArgumentBinding(storage, arg, i * 8));
 421 
 422                         if (DEBUG) {
 423                             System.out.println("Argument " + arg.getName() + " will be passed in register " + getStorageName(storage));

 424                         }
 425                         break;
 426 
 427                     case SSE: {
 428                         int width = 8;
 429 
 430                         for (int j = i + 1; j < info.getClasses().size(); j++) {
 431                             if (info.getClasses().get(j) == ArgumentClass.SSEUP) {
 432                                 width += 8;
 433                             }
 434                         }
 435 
 436                         if (width > 64) {
 437                             throw new IllegalArgumentException((width * 8) + "-bit vector arguments not supported");
 438                         }
 439 
 440                         storage = new Storage(forArguments ? StorageClass.VECTOR_ARGUMENT_REGISTER : StorageClass.VECTOR_RETURN_REGISTER, nVectorRegs++, width);
 441                         bindings[storage.getStorageClass().ordinal()].add(new ArgumentBinding(storage, arg, i * 8));


 442 
 443                         if (DEBUG) {
 444                             System.out.println("Argument " + arg.getName() + " will be passed in register " + getStorageName(storage));

 445                         }
 446                         break;
 447                     }
 448 
 449                     case SSEUP:
 450                         break;
 451 
 452                     case X87: {
 453                         int width = 8;
 454 
 455                         if (i < info.getClasses().size() && info.getClasses().get(i + 1) == ArgumentClass.X87UP) {
 456                             width += 8;
 457                         }
 458 
 459                         assert !forArguments;
 460 
 461                         storage = new Storage(StorageClass.X87_RETURN_REGISTER, nX87Regs++, width);
 462                         bindings[storage.getStorageClass().ordinal()].add(new ArgumentBinding(storage, arg, i * 8));
 463 
 464                         if (DEBUG) {
 465                             System.out.println("Argument " + arg.getName() + " will be passed in register " + getStorageName(storage));

 466                         }
 467                         break;
 468                     }
 469 
 470                     case X87UP:
 471                         break;
 472 
 473                     default:
 474                         throw new UnsupportedOperationException("Unhandled class " + c);
 475                     }
 476                 }
 477             }
 478         }
 479     }
 480 
 481     private void addBindings(ArrayList<Argument> members, StorageCalculator calculator) {
 482         members.stream().forEach(arg -> calculator.addBindings(arg, examineArgument(calculator.forArguments, arg.getType())));
 483     }
 484 
 485     public CallingSequence arrangeCall(NativeMethodType nmt) {
 486         return arrangeCall(nmt.returnType() == NativeTypes.VOID ? null : nmt.returnType().layout(),
 487                 Stream.of(nmt.parameterArray()).map(LayoutType::layout).toArray(Layout[]::new));
 488     }
 489 
 490     public CallingSequence arrangeCall(Layout ret, Layout... params) {
 491         ArrayList<Argument> returns = new ArrayList<>();
 492         ArrayList<Argument> args = new ArrayList<>();
 493         boolean returnsInMemory = false;
 494 
 495         if (ret != null) {
 496             returnsInMemory = examineArgument(false, ret).inMemory();
 497 
 498             // In some cases the return is passed in as first implicit pointer argument, and a corresponding pointer type is returned
 499             if (returnsInMemory) {
 500                 args = new ArrayList<>();
 501 
 502                 Argument returnPointer = new Argument(-1, Address.ofLayout(64, ret), "__retval");
 503                 args.add(returnPointer);
 504                 returns.add(returnPointer);
 505             } else {
 506                 returns.add(new Argument(-1, ret, "__retval"));
 507             }
 508         }
 509 
 510         for (int i = 0; i < params.length; i++) {
 511             args.add(new Argument(i, params[i], "arg" + i));
 512         }
 513 
 514         @SuppressWarnings("unchecked")
 515         ArrayList<ArgumentBinding>[] bindings = (ArrayList<ArgumentBinding>[]) new ArrayList<?>[StorageClass.values().length];
 516 
 517         for (int i = 0; i < StorageClass.values().length; i++) {
 518             bindings[i] = new ArrayList<>();
 519         }
 520 
 521         addBindings(args, new StorageCalculator(bindings, true));
 522         addBindings(returns, new StorageCalculator(bindings, false));
 523 
 524         return new CallingSequence(params.length, bindings, returnsInMemory);
 525     }
 526 }


   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 package jdk.internal.foreign.abi.x64.sysv;
  24 


  25 import java.foreign.layout.Address;
  26 import java.foreign.layout.Group;
  27 import java.foreign.layout.Group.Kind;
  28 import java.foreign.layout.Layout;
  29 import java.foreign.layout.Padding;
  30 import java.foreign.layout.Sequence;
  31 import java.foreign.layout.Value;

  32 import java.util.ArrayList;
  33 import java.util.List;
  34 import java.util.function.BiConsumer;
  35 
  36 import jdk.internal.foreign.Util;
  37 import jdk.internal.foreign.abi.Argument;
  38 import jdk.internal.foreign.abi.ArgumentBinding;
  39 import jdk.internal.foreign.abi.CallingSequenceBuilder;
  40 import jdk.internal.foreign.abi.Storage;
  41 import jdk.internal.foreign.abi.StorageClass;

  42 import jdk.internal.foreign.abi.x64.ArgumentClass;
  43 import jdk.internal.foreign.abi.x64.SharedUtils;
  44 
  45 import static sun.security.action.GetBooleanAction.privilegedGetProperty;
  46 
  47 public class CallingSequenceBuilderImpl extends CallingSequenceBuilder {
  48 
  49     private static final SharedUtils.StorageDebugHelper storageDbgHelper = new SharedUtils.StorageDebugHelper(
  50             new String[] { "rdi", "rsi", "rdx", "rcx", "r8", "r9" },
  51             new String[] { "rax", "rdx" },
  52             new String[] { "st0", "st1" },
  53             SysVx64ABI.MAX_VECTOR_ARGUMENT_REGISTERS,
  54             SysVx64ABI.MAX_VECTOR_RETURN_REGISTERS
  55     );
  56 
  57     private static final boolean DEBUG =
  58         privilegedGetProperty("jdk.internal.foreign.abi.x64.sysv.DEBUG");
  59 
  60     // The AVX 512 enlightened ABI says "eight eightbytes"
  61     // Although AMD64 0.99.6 states 4 eightbytes
  62     private static final int MAX_AGGREGATE_REGS_SIZE = 8;
  63 
  64     private static final ArrayList<ArgumentClass> COMPLEX_X87_CLASSES;

  65 
  66     static {
  67         COMPLEX_X87_CLASSES = new ArrayList<>();
  68         COMPLEX_X87_CLASSES.add(ArgumentClass.X87);
  69         COMPLEX_X87_CLASSES.add(ArgumentClass.X87UP);
  70         COMPLEX_X87_CLASSES.add(ArgumentClass.X87);
  71         COMPLEX_X87_CLASSES.add(ArgumentClass.X87UP);
  72     }
  73 
  74     public CallingSequenceBuilderImpl(Layout layout) {
  75         this(layout, new StorageCalculator(false), new StorageCalculator(true));

  76     }
  77 
  78     private CallingSequenceBuilderImpl(Layout layout, StorageCalculator retCalculator, StorageCalculator argCalculator) {
  79         super(layout, retCalculator::addBindings, argCalculator::addBindings, argCalculator::addBindings);











  80     }
  81 
  82     @Override
  83     protected ArgumentInfo makeArgument(Layout layout, int pos, String name) {
  84         return new ArgumentInfo(layout, pos, name);

  85     }
  86 
  87     static class ArgumentInfo extends Argument {
  88         private final List<ArgumentClass> classes;
  89 
  90         public ArgumentInfo(Layout layout, int argumentIndex, String debugName) {
  91             super(layout, argumentIndex, debugName);
  92             this.classes = classifyType(layout);
  93         }
  94 
  95         public int getIntegerRegs() {
  96             return (int)classes.stream()
  97                     .filter(cl -> cl == ArgumentClass.INTEGER)
  98                     .count();
  99         }
 100 
 101         public int getVectorRegs() {
 102             return (int)classes.stream()
 103                     .filter(cl -> cl == ArgumentClass.SSE)
 104                     .count();
 105         }
 106 
 107         @Override
 108         public boolean inMemory() {
 109             return classes.stream().allMatch(this::isMemoryClass);
 110         }
 111 
 112         private boolean isMemoryClass(ArgumentClass cl) {
 113             return cl == ArgumentClass.MEMORY ||
 114                     (argumentIndex() != -1 &&
 115                             (cl == ArgumentClass.X87 || cl == ArgumentClass.X87UP));
 116         }
 117 
 118         public List<ArgumentClass> getClasses() {
 119             return classes;
 120         }


 121     }
 122 
 123     private static List<ArgumentClass> classifyValueType(Value type) {
 124         ArrayList<ArgumentClass> classes = new ArrayList<>();
 125 
 126         switch (type.kind()) {
 127             case INTEGRAL_SIGNED: case INTEGRAL_UNSIGNED:
 128                 classes.add(ArgumentClass.INTEGER);
 129                 // int128
 130                 long left = (type.bitsSize() / 8) - 8;
 131                 while (left > 0) {
 132                     classes.add(ArgumentClass.INTEGER);
 133                     left -= 8;
 134                 }
 135                 return classes;
 136             case FLOATING_POINT:
 137                 if ((type.bitsSize() / 8) > 8) {
 138                     classes.add(ArgumentClass.X87);
 139                     classes.add(ArgumentClass.X87UP);
 140                     return classes;
 141                 } else {
 142                     classes.add(ArgumentClass.SSE);
 143                     return classes;
 144                 }
 145             default:
 146                 throw new IllegalArgumentException("Type " + type + " is not yet supported");
 147         }
 148     }
 149 
 150     private static List<ArgumentClass> classifyArrayType(Sequence type) {
 151         long nWords = Util.alignUp((type.bitsSize() / 8), 8) / 8;
 152         if (nWords > MAX_AGGREGATE_REGS_SIZE) {
 153             return createMemoryClassArray(nWords);
 154         }
 155 
 156         ArrayList<ArgumentClass> classes = new ArrayList<>();
 157 
 158         for (long i = 0; i < nWords; i++) {
 159             classes.add(ArgumentClass.NO_CLASS);
 160         }
 161 
 162         long offset = 0;
 163         final long count = type.elementsSize();
 164         for (long idx = 0; idx < count; idx++) {
 165             Layout t = type.element();
 166             offset = SharedUtils.align(t, false, offset);
 167             List<ArgumentClass> subclasses = classifyType(t);
 168             if (subclasses.isEmpty()) {
 169                 return classes;
 170             }
 171 
 172             for (int i = 0; i < subclasses.size(); i++) {
 173                 int pos = (int)(offset / 8);
 174                 ArgumentClass newClass = classes.get(i + pos).merge(subclasses.get(i));
 175                 classes.set(i + pos, newClass);
 176             }
 177 
 178             offset += t.bitsSize() / 8;
 179         }
 180 
 181         for (int i = 0; i < classes.size(); i++) {
 182             ArgumentClass c = classes.get(i);
 183 
 184             if (c == ArgumentClass.MEMORY) {
 185                 return createMemoryClassArray(classes.size());
 186             }
 187 


 196             }
 197         }
 198 
 199         if (classes.size() > 2) {
 200             if (classes.get(0) != ArgumentClass.SSE) {
 201                 return createMemoryClassArray(classes.size());
 202             }
 203 
 204             for (int i = 1; i < classes.size(); i++) {
 205                 if (classes.get(i) != ArgumentClass.SSEUP) {
 206                     return createMemoryClassArray(classes.size());
 207                 }
 208             }
 209         }
 210 
 211         return classes;
 212     }
 213 
 214     // TODO: handle zero length arrays
 215     // TODO: Handle nested structs (and primitives)
 216     private static List<ArgumentClass> classifyStructType(Group type) {
 217         long nWords = Util.alignUp((type.bitsSize() / 8), 8) / 8;
 218         if (nWords > MAX_AGGREGATE_REGS_SIZE) {
 219             return createMemoryClassArray(nWords);
 220         }
 221 
 222         ArrayList<ArgumentClass> classes = new ArrayList<>();
 223 
 224         for (long i = 0; i < nWords; i++) {
 225             classes.add(ArgumentClass.NO_CLASS);
 226         }
 227 
 228         long offset = 0;
 229         final int count = type.elements().size();
 230         for (int idx = 0; idx < count; idx++) {
 231             Layout t = type.elements().get(idx);
 232             if (t instanceof Padding) {
 233                 continue;
 234             }
 235             // ignore zero-length array for now
 236             // TODO: handle zero length arrays here
 237             if (t instanceof Sequence) {
 238                 if (((Sequence) t).elementsSize() == 0) {
 239                     continue;
 240                 }
 241             }
 242             offset = SharedUtils.align(t, false, offset);
 243             List<ArgumentClass> subclasses = classifyType(t);
 244             if (subclasses.isEmpty()) {
 245                 return classes;
 246             }
 247 
 248             for (int i = 0; i < subclasses.size(); i++) {
 249                 int pos = (int)(offset / 8);
 250                 ArgumentClass newClass = classes.get(i + pos).merge(subclasses.get(i));
 251                 classes.set(i + pos, newClass);
 252             }
 253 
 254             // TODO: validate union strategy is sound
 255             if (type.kind() != Kind.UNION) {
 256                 offset += t.bitsSize() / 8;
 257             }
 258         }
 259 
 260         for (int i = 0; i < classes.size(); i++) {
 261             ArgumentClass c = classes.get(i);
 262 
 263             if (c == ArgumentClass.MEMORY) {


 273                     return createMemoryClassArray(classes.size());
 274                 }
 275             }
 276         }
 277 
 278         if (classes.size() > 2) {
 279             if (classes.get(0) != ArgumentClass.SSE) {
 280                 return createMemoryClassArray(classes.size());
 281             }
 282 
 283             for (int i = 1; i < classes.size(); i++) {
 284                 if (classes.get(i) != ArgumentClass.SSEUP) {
 285                     return createMemoryClassArray(classes.size());
 286                 }
 287             }
 288         }
 289 
 290         return classes;
 291     }
 292 
 293     private static List<ArgumentClass> classifyType(Layout type) {
 294         try {
 295             if (type instanceof Value) {
 296                 return classifyValueType((Value) type);
 297             } else if (type instanceof Address) {
 298                 ArrayList<ArgumentClass> classes = new ArrayList<>();
 299                 classes.add(ArgumentClass.INTEGER);
 300                 return classes;
 301             } else if (type instanceof Sequence) {
 302                 return classifyArrayType((Sequence) type);
 303             } else if (type instanceof Group) {
 304                 return type.name().isPresent() && type.name().get().equals("LongDoubleComplex") ?
 305                         COMPLEX_X87_CLASSES :
 306                         classifyStructType((Group) type);
 307             } else {
 308                 throw new IllegalArgumentException("Unhandled type " + type);
 309             }
 310         } catch (UnsupportedOperationException e) {
 311             System.err.println("Failed to classify layout: " + type);
 312             throw e;
 313         }
 314     }
 315 
 316     private static List<ArgumentClass> createMemoryClassArray(long n) {
 317         ArrayList<ArgumentClass> classes = new ArrayList<>();
 318         for (int i = 0; i < n; i++) {
 319             classes.add(ArgumentClass.MEMORY);
 320         }
 321 
 322         return classes;
 323     }
 324 
 325     static class StorageCalculator {







































 326         private final boolean forArguments;
 327 
 328         private int nIntegerRegs = 0;
 329         private int nVectorRegs = 0;
 330         private int nX87Regs = 0;
 331         private long stackOffset = 0;
 332 
 333         StorageCalculator(boolean forArguments) {

 334             this.forArguments = forArguments;
 335         }
 336 
 337         public void addBindings(Argument arg, BiConsumer<StorageClass, ArgumentBinding> bindingConsumer) {
 338             ArgumentInfo info = (ArgumentInfo)arg;
 339             if (info.inMemory() ||
 340                     nIntegerRegs + info.getIntegerRegs() > (forArguments ? SysVx64ABI.MAX_INTEGER_ARGUMENT_REGISTERS : SysVx64ABI.MAX_INTEGER_RETURN_REGISTERS) ||
 341                     nVectorRegs + info.getVectorRegs() > (forArguments ? SysVx64ABI.MAX_VECTOR_ARGUMENT_REGISTERS : SysVx64ABI.MAX_VECTOR_RETURN_REGISTERS)) {
 342                 // stack
 343 
 344                 long alignment = Math.max(SharedUtils.alignment(info.layout(), true), 8);
 345 
 346                 long newStackOffset = Util.alignUp(stackOffset, alignment);





 347                 stackOffset = newStackOffset;
 348 
 349                 long tmpStackOffset = stackOffset;
 350                 for (int i = 0; i < info.getClasses().size(); i++) {
 351                     Storage storage = new Storage(StorageClass.STACK_ARGUMENT_SLOT, tmpStackOffset / 8, 8);
 352                     bindingConsumer.accept(StorageClass.STACK_ARGUMENT_SLOT, new ArgumentBinding(storage, info, i * 8));
 353 
 354                     if (DEBUG) {
 355                         System.out.println("Argument " + info.name() + " will be passed on stack at offset " + tmpStackOffset);
 356                     }
 357 
 358                     tmpStackOffset += 8;
 359                 }
 360 
 361                 stackOffset += info.layout().bitsSize() / 8;
 362             } else {
 363                 // regs
 364                 for (int i = 0; i < info.getClasses().size(); i++) {
 365                     Storage storage;
 366 
 367                     ArgumentClass c = info.getClasses().get(i);
 368 
 369                     switch (c) {
 370                     case INTEGER:
 371                         storage = new Storage(forArguments ? StorageClass.INTEGER_ARGUMENT_REGISTER : StorageClass.INTEGER_RETURN_REGISTER, nIntegerRegs++, SharedUtils.INTEGER_REGISTER_SIZE);
 372                         bindingConsumer.accept(storage.getStorageClass(), new ArgumentBinding(storage, info, i * 8));
 373 
 374                         if (DEBUG) {
 375                             System.out.println("Argument " + info.name() + " will be passed in register " +
 376                                     storageDbgHelper.getStorageName(storage));
 377                         }
 378                         break;
 379 
 380                     case SSE: {
 381                         int width = 8;
 382 
 383                         for (int j = i + 1; j < info.getClasses().size(); j++) {
 384                             if (info.getClasses().get(j) == ArgumentClass.SSEUP) {
 385                                 width += 8;
 386                             }
 387                         }
 388 
 389                         if (width > 64) {
 390                             throw new IllegalArgumentException((width * 8) + "-bit vector arguments not supported");
 391                         }
 392 
 393                         storage = new Storage(forArguments ? StorageClass.VECTOR_ARGUMENT_REGISTER : StorageClass.VECTOR_RETURN_REGISTER,
 394                                 nVectorRegs++, width, SharedUtils.VECTOR_REGISTER_SIZE);
 395 
 396                         bindingConsumer.accept(storage.getStorageClass(), new ArgumentBinding(storage, info, i * 8));
 397 
 398                         if (DEBUG) {
 399                             System.out.println("Argument " + info.name() + " will be passed in register " +
 400                                     storageDbgHelper.getStorageName(storage));
 401                         }
 402                         break;
 403                     }
 404 
 405                     case SSEUP:
 406                         break;
 407 
 408                     case X87: {
 409                         int width = 8;
 410 
 411                         if (i < info.getClasses().size() && info.getClasses().get(i + 1) == ArgumentClass.X87UP) {
 412                             width += 8;
 413                         }
 414 
 415                         assert !forArguments;
 416 
 417                         storage = new Storage(StorageClass.X87_RETURN_REGISTER, nX87Regs++, width, SharedUtils.X87_REGISTER_SIZE);
 418                         bindingConsumer.accept(storage.getStorageClass(), new ArgumentBinding(storage, info, i * 8));
 419 
 420                         if (DEBUG) {
 421                             System.out.println("Argument " + info.name() + " will be passed in register " +
 422                                     storageDbgHelper.getStorageName(storage));
 423                         }
 424                         break;
 425                     }
 426 
 427                     case X87UP:
 428                         break;
 429 
 430                     default:
 431                         throw new UnsupportedOperationException("Unhandled class " + c);
 432                     }
 433                 }
 434             }
 435         }














































 436     }
 437 }
< prev index next >