1 /*
   2  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   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 
  24 /*
  25  * @test
  26  * @modules java.base/jdk.internal.foreign.abi java.base/jdk.internal.foreign.memory java.base/jdk.internal.foreign.abi.x64.sysv
  27  */
  28 
  29 import java.foreign.NativeTypes;
  30 import java.foreign.layout.Group;
  31 import java.foreign.layout.Layout;
  32 import java.foreign.memory.LayoutType;
  33 import java.util.ArrayList;
  34 import java.util.List;
  35 import java.util.stream.Stream;
  36 
  37 import jdk.internal.foreign.abi.CallingSequence;
  38 import jdk.internal.foreign.abi.StorageClass;
  39 import jdk.internal.foreign.abi.x64.sysv.CallingSequenceBuilderImpl;
  40 import jdk.internal.foreign.abi.x64.sysv.SysVx64ABI;
  41 import jdk.internal.foreign.memory.Types;
  42 
  43 public class StandardCallTest {
  44 
  45     public StandardCallTest() {
  46     }
  47 
  48     public void testInteger() {
  49         CallingSequenceBuilderImpl sc = new CallingSequenceBuilderImpl(null);
  50 
  51         // Fill registers and spill over with 2 args on stack
  52         LayoutType<?> args[] = new LayoutType<?>[SysVx64ABI.MAX_INTEGER_ARGUMENT_REGISTERS + 2];
  53         for (int i = 0; i < SysVx64ABI.MAX_INTEGER_ARGUMENT_REGISTERS + 2; i++) {
  54             args[i] = NativeTypes.INT64;
  55         }
  56 
  57         Stream.of(args).map(LayoutType::layout).forEach(sc::addArgument);
  58         CallingSequence recipe = sc.build();
  59 
  60         assertEquals(false, recipe.returnsInMemory());
  61         assertEquals(SysVx64ABI.MAX_INTEGER_ARGUMENT_REGISTERS, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).size());
  62         assertEquals(0, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).size());
  63         assertEquals(2, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).size());
  64 
  65         for (int i = 0; i < SysVx64ABI.MAX_INTEGER_ARGUMENT_REGISTERS; i++) {
  66             assertEquals(args[i].layout(), recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(i).argument().layout());
  67             assertEquals(0, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(i).offset());
  68         }
  69 
  70         for (int i = 0; i < 2; i++) {
  71             assertEquals(args[SysVx64ABI.MAX_INTEGER_ARGUMENT_REGISTERS + i].layout(),
  72                     recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(i).argument().layout());
  73             assertEquals(0, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(i).offset());
  74         }
  75     }
  76 
  77     public void testSse() {
  78         CallingSequenceBuilderImpl sc = new CallingSequenceBuilderImpl(null);
  79 
  80         // Fill registers and spill over with 2 args on stack
  81         LayoutType<?> args[] = new LayoutType<?>[SysVx64ABI.MAX_VECTOR_ARGUMENT_REGISTERS + 2];
  82         for (int i = 0; i < SysVx64ABI.MAX_VECTOR_ARGUMENT_REGISTERS + 2; i++) {
  83             args[i] = NativeTypes.IEEE_FLOAT32;
  84         }
  85 
  86         Stream.of(args).map(LayoutType::layout).forEach(sc::addArgument);
  87 
  88         CallingSequence recipe = sc.build();
  89 
  90         assertEquals(false, recipe.returnsInMemory());
  91         assertEquals(0, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).size());
  92         assertEquals(SysVx64ABI.MAX_VECTOR_ARGUMENT_REGISTERS, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).size());
  93         assertEquals(2, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).size());
  94 
  95         for (int i = 0; i < SysVx64ABI.MAX_VECTOR_ARGUMENT_REGISTERS; i++) {
  96             assertEquals(args[i].layout(), recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(i).argument().layout());
  97             assertEquals(0, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(i).offset());
  98         }
  99 
 100         for (int i = 0; i < 2; i++) {
 101             assertEquals(args[SysVx64ABI.MAX_VECTOR_ARGUMENT_REGISTERS + i].layout(),
 102                     recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(i).argument().layout());
 103             assertEquals(0, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(i).offset());
 104         }
 105     }
 106 
 107      public void testMixed() {
 108         CallingSequenceBuilderImpl sc = new CallingSequenceBuilderImpl(null);
 109 
 110         // Fill GP registers + 2 on stack
 111         List<LayoutType<?>> args = new ArrayList<>();
 112         for (int i = 0; i < SysVx64ABI.MAX_INTEGER_ARGUMENT_REGISTERS + 2; i++) {
 113             args.add(NativeTypes.INT64);
 114         }
 115 
 116         // Fill SSE registers + 2 on stack
 117         for (int i = 0; i < SysVx64ABI.MAX_VECTOR_ARGUMENT_REGISTERS + 2; i++) {
 118             args.add(NativeTypes.IEEE_FLOAT32);
 119         }
 120 
 121         args.stream().map(LayoutType::layout).forEach(sc::addArgument);
 122 
 123         CallingSequence recipe = sc.build();
 124 
 125         assertEquals(false, recipe.returnsInMemory());
 126         assertEquals(SysVx64ABI.MAX_INTEGER_ARGUMENT_REGISTERS, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).size());
 127         assertEquals(SysVx64ABI.MAX_VECTOR_ARGUMENT_REGISTERS, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).size());
 128         assertEquals(4, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).size());
 129 
 130         int arg = 0;
 131         for (int i = 0; i < SysVx64ABI.MAX_INTEGER_ARGUMENT_REGISTERS; i++, arg++) {
 132             assertEquals(args.get(arg).layout(), recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(i).argument().layout());
 133             assertEquals(0, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(i).offset());
 134         }
 135 
 136         for (int i = 0; i < 2; i++, arg++) {
 137             assertEquals(args.get(arg).layout(), recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(i).argument().layout());
 138             assertEquals(0, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(i).offset());
 139         }
 140 
 141         for (int i = 0; i < SysVx64ABI.MAX_VECTOR_ARGUMENT_REGISTERS; i++, arg++) {
 142             assertEquals(args.get(arg).layout(), recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(i).argument().layout());
 143             assertEquals(0, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(i).offset());
 144         }
 145 
 146         for (int i = 2; i < 4; i++, arg++) {
 147             assertEquals(args.get(arg).layout(), recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(i).argument().layout());
 148             assertEquals(0, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(i).offset());
 149         }
 150     }
 151 
 152     /**
 153      * This is the example from the System V ABI AMD64 document
 154      *
 155      * struct structparm {
 156      *   int32_t a, int32_t b, double d;
 157      * } s;
 158      * int32_t e, f, g, h, i, j, k;
 159      * long double ld;
 160      * double m, n;
 161      * __m256 y;
 162      *
 163      * void m(e, f, s, g, h, ld, m, y, n, i, j, k);
 164      *
 165      * m(s);
 166      */
 167     public void testAbiExample() {
 168         Layout[] args = { Types.INT32, Types.INT32, Group.struct(Types.INT32, Types.INT32, Types.DOUBLE),
 169                 Types.INT32, Types.INT32, Types.LONG_DOUBLE, Types.DOUBLE,
 170                 Types.DOUBLE, Types.INT32, Types.INT32, Types.INT32 };
 171 
 172         CallingSequenceBuilderImpl sc = new CallingSequenceBuilderImpl(null);
 173         Stream.of(args).forEach(sc::addArgument);
 174         CallingSequence recipe = sc.build();
 175 
 176         assertEquals(false, recipe.returnsInMemory());
 177         assertEquals(6, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).size());
 178         assertEquals(3, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).size());
 179         assertEquals(4, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).size());
 180 
 181         // e
 182         assertEquals(args[0], recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).argument().layout());
 183         assertEquals(0, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).offset());
 184 
 185         // f
 186         assertEquals(args[1], recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(1).argument().layout());
 187         assertEquals(0, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(1).offset());
 188 
 189         // s.a & s.b
 190         assertEquals(args[2], recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(2).argument().layout());
 191         assertEquals(0, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(2).offset());
 192 
 193         // s.d
 194         assertEquals(args[2], recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(0).argument().layout());
 195         assertEquals(8, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(0).offset());
 196 
 197         // g
 198         assertEquals(args[3], recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(3).argument().layout());
 199         assertEquals(0, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(3).offset());
 200 
 201         // h
 202         assertEquals(args[4], recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(4).argument().layout());
 203         assertEquals(0, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(4).offset());
 204 
 205         // ld
 206         assertEquals(args[5], recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(0).argument().layout());
 207         assertEquals(0, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(0).offset());
 208         assertEquals(args[5], recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(1).argument().layout());
 209         assertEquals(8, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(1).offset());
 210 
 211         // m
 212         assertEquals(args[6], recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(1).argument().layout());
 213         assertEquals(0, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(1).offset());
 214 
 215         // n
 216         assertEquals(args[7], recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(2).argument().layout());
 217         assertEquals(0, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(2).offset());
 218 
 219         // i
 220         assertEquals(args[8], recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(5).argument().layout());
 221         assertEquals(0, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(5).offset());
 222 
 223         // j
 224         assertEquals(args[9], recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(2).argument().layout());
 225         assertEquals(0, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(2).offset());
 226 
 227         // k
 228         assertEquals(args[10], recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(3).argument().layout());
 229         assertEquals(0, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(3).offset());
 230     }
 231 
 232     /**
 233      * This is a varargs example from the System V ABI AMD64 document
 234      *
 235      * int a, b;
 236      * long double ld;
 237      * double m, n;
 238      * __m256 u, y;
 239      *
 240      * extern void func (int a, double m, __m256 u, ...);
 241      *
 242      * func(a, m, u, b, ld, y, n);
 243      */
 244     public void testAbiExampleVarargs() {
 245         Layout[] args = {
 246                 Types.INT,
 247                 Types.DOUBLE,
 248                 Types.INT,
 249                 Types.LONG_DOUBLE,
 250                 Types.DOUBLE };
 251         CallingSequenceBuilderImpl sc = new CallingSequenceBuilderImpl(null);
 252         Stream.of(args).forEach(sc::addArgument);
 253         CallingSequence recipe = sc.build();
 254 
 255         assertEquals(false, recipe.returnsInMemory());
 256         assertEquals(2, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).size());
 257         assertEquals(2, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).size());
 258         assertEquals(2, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).size());
 259 
 260 
 261         // a
 262         assertEquals(args[0], recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).argument().layout());
 263         assertEquals(0, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).offset());
 264 
 265         // m
 266         assertEquals(args[1], recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(0).argument().layout());
 267         assertEquals(0, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(0).offset());
 268 
 269         // b
 270         assertEquals(args[2], recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(1).argument().layout());
 271         assertEquals(0, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(1).offset());
 272 
 273         // ld
 274         assertEquals(args[3], recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(0).argument().layout());
 275         assertEquals(0, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(0).offset());
 276         assertEquals(args[3], recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(1).argument().layout());
 277         assertEquals(8, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(1).offset());
 278 
 279         // n
 280         assertEquals(args[4], recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(1).argument().layout());
 281         assertEquals(0, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(1).offset());
 282     }
 283 
 284 
 285     /**
 286      * struct s {
 287      *   uint64_t u0;
 288      * } s;
 289      *
 290      * void m(struct s s);
 291      *
 292      * m(s);
 293      */
 294     public void testStruct8() {
 295         Group structparm = Group.struct(Types.UNSIGNED.INT64);
 296 
 297         CallingSequence recipe = new CallingSequenceBuilderImpl(null)
 298                 .addArgument(structparm)
 299                 .build();
 300 
 301         assertEquals(false, recipe.returnsInMemory());
 302         assertEquals(1, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).size());
 303         assertEquals(0, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).size());
 304         assertEquals(0, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).size());
 305 
 306         // s.u0
 307         assertEquals(structparm, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).argument().layout());
 308         assertEquals(0, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).offset());
 309     }
 310 
 311     /**
 312      * struct s {
 313      *   uint64_t u0, u1;
 314      * } s;
 315      *
 316      * void m(struct s s);
 317      *
 318      * m(s);
 319      */
 320     public void testStruct16() {
 321         Group structparm = Group.struct(Types.UNSIGNED.INT64, Types.UNSIGNED.INT64);
 322 
 323         CallingSequence recipe = new CallingSequenceBuilderImpl(null)
 324                 .addArgument(structparm)
 325                 .build();
 326 
 327         assertEquals(false, recipe.returnsInMemory());
 328         assertEquals(2, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).size());
 329         assertEquals(0, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).size());
 330         assertEquals(0, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).size());
 331 
 332         // s.u0
 333         assertEquals(structparm, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).argument().layout());
 334         assertEquals(0, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).offset());
 335 
 336         // s.u1
 337         assertEquals(structparm, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(1).argument().layout());
 338         assertEquals(8, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(1).offset());
 339     }
 340 
 341     /**
 342      * struct s {
 343      *   uint64_t u0, u1, u2;
 344      * } s;
 345      *
 346      * void m(struct s s);
 347      *
 348      * m(s);
 349      */
 350     public void testStruct24() {
 351         Group structparm = Group.struct(Types.UNSIGNED.INT64, Types.UNSIGNED.INT64, Types.UNSIGNED.INT64);
 352 
 353         CallingSequence recipe = new CallingSequenceBuilderImpl(null)
 354                 .addArgument(structparm)
 355                 .build();
 356 
 357         assertEquals(false, recipe.returnsInMemory());
 358         assertEquals(0, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).size());
 359         assertEquals(0, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).size());
 360         assertEquals(3, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).size());
 361 
 362         // s.u0
 363         assertEquals(structparm, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(0).argument().layout());
 364         assertEquals(0, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(0).offset());
 365 
 366         // s.u1
 367         assertEquals(structparm, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(1).argument().layout());
 368         assertEquals(8, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(1).offset());
 369 
 370         // s.u2
 371         assertEquals(structparm, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(2).argument().layout());
 372         assertEquals(16, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(2).offset());
 373     }
 374 
 375     /**
 376      * struct s {
 377      *   uint64_t u0, u1, u2, u3;
 378      * } s;
 379      *
 380      * void m(struct s s);
 381      *
 382      * m(s);
 383      */
 384     public void testStruct32() {
 385         Layout structparm = Layout.of("[u64u64u64u64]");
 386 
 387         CallingSequence recipe = new CallingSequenceBuilderImpl(null)
 388                 .addArgument(structparm)
 389                 .build();
 390 
 391         assertEquals(false, recipe.returnsInMemory());
 392         assertEquals(0, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).size());
 393         assertEquals(0, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).size());
 394         assertEquals(4, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).size());
 395 
 396         // s.u0
 397         assertEquals(structparm, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(0).argument().layout());
 398         assertEquals(0, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(0).offset());
 399 
 400         // s.u1
 401         assertEquals(structparm, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(1).argument().layout());
 402         assertEquals(8, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(1).offset());
 403 
 404         // s.u2
 405         assertEquals(structparm, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(2).argument().layout());
 406         assertEquals(16, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(2).offset());
 407 
 408         // s.u3
 409         assertEquals(structparm, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(3).argument().layout());
 410         assertEquals(24, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).get(3).offset());
 411     }
 412 
 413     /**
 414      * typedef void (*f)(void);
 415      *
 416      * void m(f f);
 417      * void f_impl(void);
 418      *
 419      * m(f_impl);
 420      */
 421     public void testFunctionType() {
 422         Layout arg = Layout.of("u64:()v");
 423 
 424         CallingSequence recipe = new CallingSequenceBuilderImpl(null)
 425                 .addArgument(arg)
 426                 .build();
 427 
 428         assertEquals(false, recipe.returnsInMemory());
 429         assertEquals(1, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).size());
 430         assertEquals(0, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).size());
 431         assertEquals(0, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).size());
 432 
 433         // s.u0
 434         assertEquals(arg, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).argument().layout());
 435         assertEquals(0, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).offset());
 436     }
 437 
 438     /**
 439      * void f(int64_t l0, float f0, __m256 m0);
 440      */
 441     public void testMixedArgs() {
 442         CallingSequence recipe = new CallingSequenceBuilderImpl(null)
 443                 .addArgument(Types.INT64)
 444                 .addArgument(Types.FLOAT)
 445                 .build();
 446 
 447         assertEquals(false, recipe.returnsInMemory());
 448         assertEquals(1, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).size());
 449         assertEquals(1, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).size());
 450         assertEquals(0, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).size());
 451 
 452         // l0
 453         assertEquals(Types.INT64, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).argument().layout());
 454         assertEquals(0, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).offset());
 455 
 456         // f0
 457         assertEquals(Types.FLOAT, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(0).argument().layout());
 458         assertEquals(0, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).get(0).offset());
 459     }
 460 
 461     /**
 462      * struct s {
 463      *    int64_t l0;
 464      *    int64_t l1;
 465      * };
 466      *
 467      * void f(struct s s1);
 468      */
 469     public void testIntegerStruct() {
 470         Layout arg = Layout.of("[i64i64]");
 471 
 472         CallingSequence recipe = new CallingSequenceBuilderImpl(null)
 473                 .addArgument(arg)
 474                 .build();
 475 
 476         assertEquals(false, recipe.returnsInMemory());
 477         assertEquals(2, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).size());
 478         assertEquals(0, recipe.bindings(StorageClass.VECTOR_ARGUMENT_REGISTER).size());
 479         assertEquals(0, recipe.bindings(StorageClass.STACK_ARGUMENT_SLOT).size());
 480 
 481         // s.l0
 482         assertEquals(arg, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).argument().layout());
 483         assertEquals(0, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(0).offset());
 484 
 485         // s.l1
 486         assertEquals(arg, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(1).argument().layout());
 487         assertEquals(8, recipe.bindings(StorageClass.INTEGER_ARGUMENT_REGISTER).get(1).offset());
 488     }
 489 
 490     static void assertEquals(long expected, long actual) {
 491         if (expected != actual) {
 492             throw new RuntimeException("expected: " + expected + " does not match actual: " + actual);
 493         }
 494     }
 495 
 496     static void assertEquals(boolean expected, boolean actual) {
 497         if (expected != actual) {
 498             throw new RuntimeException("expected: " + expected + " does not match actual: " + actual);
 499         }
 500     }
 501 
 502     static void assertEquals(Object expected, Object actual) {
 503         if (expected != actual) {
 504             throw new RuntimeException("expected: " + expected + " does not match actual: " + actual);
 505         }
 506     }
 507 
 508     public static void main(String[] args) {
 509         StandardCallTest t = new StandardCallTest();
 510 
 511         t.testInteger();
 512         t.testSse();
 513         t.testMixed();
 514         t.testAbiExample();
 515         t.testAbiExampleVarargs();
 516         t.testStruct8();
 517         t.testStruct16();
 518         t.testStruct24();
 519         t.testStruct32();
 520         t.testFunctionType();
 521         t.testMixedArgs();
 522         t.testIntegerStruct();
 523     }
 524 }