diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/LoweringPrepareAArch64CXXABI.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/LoweringPrepareAArch64CXXABI.cpp index a561bc7f2ba5..6fe71b13ff92 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/LoweringPrepareAArch64CXXABI.cpp +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/LoweringPrepareAArch64CXXABI.cpp @@ -168,6 +168,16 @@ mlir::Value LoweringPrepareAArch64CXXABI::lowerAAPCSVAArg( maybeRegBlock); auto contBlock = currentBlock->splitBlock(op); + // now contBlock should be the block after onStackBlock in CFG. + // This is essential, considering the case where originally currentBlock + // was the only block in the region. By splitting the block, and added + // above blocks, really the rear block in the region should be contBlock, + // not onStackBlock, but splitBlock would just insert contBlock after + // currentBlock, so we need to move it. + auto contBlockIter = contBlock->getIterator(); + contBlock->getParent()->getBlocks().remove(contBlockIter); + onStackBlock->getParent()->getBlocks().insertAfter( + mlir::Region::iterator(onStackBlock), contBlock); // Otherwise, at least some kind of argument could go in these registers, the // question is whether this particular type is too big. diff --git a/clang/test/CIR/CodeGen/var-arg-float.c b/clang/test/CIR/CodeGen/var-arg-float.c index 0824b9ae2915..7fc6c68fec5f 100644 --- a/clang/test/CIR/CodeGen/var-arg-float.c +++ b/clang/test/CIR/CodeGen/var-arg-float.c @@ -37,24 +37,12 @@ double f1(int n, ...) { // AFTER: [[CMP0:%.*]] = cir.cmp(ge, [[VR_OFFS]], [[ZERO]]) : !s32i, !cir.bool // AFTER-NEXT: cir.brcond [[CMP0]] [[BB_ON_STACK:\^bb.*]], [[BB_MAY_REG:\^bb.*]] - -// AFTER-NEXT: [[BB_END:\^bb.*]]([[BLK_ARG:%.*]]: !cir.ptr): // 2 preds: [[BB_IN_REG:\^bb.*]], [[BB_ON_STACK]] -// AFTER-NEXT: [[TMP0:%.*]] = cir.cast(bitcast, [[BLK_ARG]] : !cir.ptr), !cir.ptr -// AFTER-NEXT: [[TMP1:%.*]] = cir.load [[TMP0]] : !cir.ptr, !cir.double -// AFTER: cir.store [[TMP1]], [[RESP]] : !cir.double, !cir.ptr -// AFTER: cir.va.end [[VARLIST]] : !cir.ptr -// AFTER: [[RES:%.*]] = cir.load [[RESP]] : !cir.ptr, !cir.double -// AFTER: cir.store [[RES]], [[RETP]] : !cir.double, !cir.ptr -// AFTER: [[RETV:%.*]] = cir.load [[RETP]] : !cir.ptr, !cir.double -// AFTER: cir.return [[RETV]] : !cir.double - - // AFTER: [[BB_MAY_REG]]: // AFTER-NEXT: [[SIXTEEN:%.*]] = cir.const #cir.int<16> : !s32i // AFTER-NEXT: [[NEW_REG_OFFS:%.*]] = cir.binop(add, [[VR_OFFS]], [[SIXTEEN]]) : !s32i // AFTER-NEXT: cir.store [[NEW_REG_OFFS]], [[VR_OFFS_P]] : !s32i, !cir.ptr // AFTER-NEXT: [[CMP1:%.*]] = cir.cmp(le, [[NEW_REG_OFFS]], [[ZERO]]) : !s32i, !cir.bool -// AFTER-NEXT: cir.brcond [[CMP1]] [[BB_IN_REG]], [[BB_ON_STACK]] +// AFTER-NEXT: cir.brcond [[CMP1]] [[BB_IN_REG:\^bb.*]], [[BB_ON_STACK]] // AFTER: [[BB_IN_REG]]: @@ -63,7 +51,7 @@ double f1(int n, ...) { // AFTER-NEXT: [[TMP2:%.*]] = cir.cast(bitcast, [[VR_TOP]] : !cir.ptr), !cir.ptr // AFTER-NEXT: [[TMP3:%.*]] = cir.ptr_stride([[TMP2]] : !cir.ptr, [[VR_OFFS]] : !s32i), !cir.ptr // AFTER-NEXT: [[IN_REG_OUTPUT:%.*]] = cir.cast(bitcast, [[TMP3]] : !cir.ptr), !cir.ptr -// AFTER-NEXT: cir.br [[BB_END]]([[IN_REG_OUTPUT]] : !cir.ptr) +// AFTER-NEXT: cir.br [[BB_END:\^bb.*]]([[IN_REG_OUTPUT]] : !cir.ptr) // AFTER: [[BB_ON_STACK]]: @@ -76,6 +64,16 @@ double f1(int n, ...) { // AFTER-NEXT: cir.store [[NEW_STACK_V]], [[STACK_P]] : !cir.ptr, !cir.ptr> // AFTER-NEXT: cir.br [[BB_END]]([[STACK_V]] : !cir.ptr) +// AFTER-NEXT: [[BB_END]]([[BLK_ARG:%.*]]: !cir.ptr): // 2 preds: [[BB_IN_REG]], [[BB_ON_STACK]] +// AFTER-NEXT: [[TMP0:%.*]] = cir.cast(bitcast, [[BLK_ARG]] : !cir.ptr), !cir.ptr +// AFTER-NEXT: [[TMP1:%.*]] = cir.load [[TMP0]] : !cir.ptr, !cir.double +// AFTER: cir.store [[TMP1]], [[RESP]] : !cir.double, !cir.ptr +// AFTER: cir.va.end [[VARLIST]] : !cir.ptr +// AFTER: [[RES:%.*]] = cir.load [[RESP]] : !cir.ptr, !cir.double +// AFTER: cir.store [[RES]], [[RETP]] : !cir.double, !cir.ptr +// AFTER: [[RETV:%.*]] = cir.load [[RETP]] : !cir.ptr, !cir.double +// AFTER: cir.return [[RETV]] : !cir.double + // beginning block llvm code // LLVM: %struct.__va_list = type { ptr, ptr, ptr, i32, i32 } // LLVM: define double @f1(i32 %0, ...) @@ -88,32 +86,32 @@ double f1(int n, ...) { // LLVM-NEXT: [[CMP0:%.*]] = icmp sge i32 [[VR_OFFS]], 0, // LLVM-NEXT: br i1 [[CMP0]], label %[[BB_ON_STACK:.*]], label %[[BB_MAY_REG:.*]], -// LLVM: [[BB_END:.*]]: ; preds = %[[BB_ON_STACK]], %[[BB_IN_REG:.*]] -// LLVM-NEXT: [[PHIP:%.*]] = phi ptr [ [[IN_REG_OUTPUT:%.*]], %[[BB_IN_REG]] ], [ [[STACK_V:%.*]], %[[BB_ON_STACK]] ] -// LLVM-NEXT: [[PHIV:%.*]] = load double, ptr [[PHIP]], align 8, -// LLVM-NEXT: store double [[PHIV]], ptr [[RESP]], align 8, -// LLVM: call void @llvm.va_end.p0(ptr [[VARLIST]]), -// LLVM: [[RES:%.*]] = load double, ptr [[RESP]], align 8, -// LLVM: store double [[RES]], ptr [[RETP]], align 8, -// LLVM: [[RETV:%.*]] = load double, ptr [[RETP]], align 8, -// LLVM-NEXT: ret double [[RETV]], - // LLVM: [[BB_MAY_REG]]: ; // LLVM-NEXT: [[NEW_REG_OFFS:%.*]] = add i32 [[VR_OFFS]], 16, // LLVM-NEXT: store i32 [[NEW_REG_OFFS]], ptr [[VR_OFFS_P]], align 4, // LLVM-NEXT: [[CMP1:%.*]] = icmp sle i32 [[NEW_REG_OFFS]], 0, -// LLVM-NEXT: br i1 [[CMP1]], label %[[BB_IN_REG]], label %[[BB_ON_STACK]], +// LLVM-NEXT: br i1 [[CMP1]], label %[[BB_IN_REG:.*]], label %[[BB_ON_STACK]], // LLVM: [[BB_IN_REG]]: ; // LLVM-NEXT: [[VR_TOP_P:%.*]] = getelementptr %struct.__va_list, ptr [[VARLIST]], i32 0, i32 2, // LLVM-NEXT: [[VR_TOP:%.*]] = load ptr, ptr [[VR_TOP_P]], align 8, // LLVM-NEXT: [[EXT64_VR_OFFS:%.*]] = sext i32 [[VR_OFFS]] to i64, -// LLVM-NEXT: [[IN_REG_OUTPUT]] = getelementptr i8, ptr [[VR_TOP]], i64 [[EXT64_VR_OFFS]], -// LLVM-NEXT: br label %[[BB_END]], +// LLVM-NEXT: [[IN_REG_OUTPUT:%.*]] = getelementptr i8, ptr [[VR_TOP]], i64 [[EXT64_VR_OFFS]], +// LLVM-NEXT: br label %[[BB_END:.*]], // LLVM: [[BB_ON_STACK]]: ; // LLVM-NEXT: [[STACK_P:%.*]] = getelementptr %struct.__va_list, ptr [[VARLIST]], i32 0, i32 0, -// LLVM-NEXT: [[STACK_V]] = load ptr, ptr [[STACK_P]], align 8, +// LLVM-NEXT: [[STACK_V:%.*]] = load ptr, ptr [[STACK_P]], align 8, // LLVM-NEXT: [[NEW_STACK_V:%.*]] = getelementptr i8, ptr [[STACK_V]], i32 8, // LLVM-NEXT: store ptr [[NEW_STACK_V]], ptr [[STACK_P]], align 8, // LLVM-NEXT: br label %[[BB_END]], + +// LLVM: [[BB_END]]: ; preds = %[[BB_ON_STACK]], %[[BB_IN_REG]] +// LLVM-NEXT: [[PHIP:%.*]] = phi ptr [ [[IN_REG_OUTPUT]], %[[BB_IN_REG]] ], [ [[STACK_V]], %[[BB_ON_STACK]] ] +// LLVM-NEXT: [[PHIV:%.*]] = load double, ptr [[PHIP]], align 8, +// LLVM-NEXT: store double [[PHIV]], ptr [[RESP]], align 8, +// LLVM: call void @llvm.va_end.p0(ptr [[VARLIST]]), +// LLVM: [[RES:%.*]] = load double, ptr [[RESP]], align 8, +// LLVM: store double [[RES]], ptr [[RETP]], align 8, +// LLVM: [[RETV:%.*]] = load double, ptr [[RETP]], align 8, +// LLVM-NEXT: ret double [[RETV]], diff --git a/clang/test/CIR/CodeGen/var-arg-scope.c b/clang/test/CIR/CodeGen/var-arg-scope.c new file mode 100644 index 000000000000..abea8ec6b9e1 --- /dev/null +++ b/clang/test/CIR/CodeGen/var-arg-scope.c @@ -0,0 +1,105 @@ +// RUN: %clang_cc1 -triple aarch64-none-linux-android21 -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-lowering-prepare %s -o %t.cir 2>&1 | FileCheck %s -check-prefix=BEFORE +// RUN: %clang_cc1 -triple aarch64-none-linux-android21 -fclangir -emit-cir -mmlir --mlir-print-ir-after=cir-lowering-prepare %s -o %t.cir 2>&1 | FileCheck %s -check-prefix=AFTER +// RUN: %clang_cc1 -triple aarch64-none-linux-android21 -fclangir -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM + +void f1(__builtin_va_list c) { + { __builtin_va_arg(c, void *); } +} + +// BEFORE: cir.func @f1(%arg0: !ty_22__va_list22) attributes +// BEFORE: [[VAR_LIST:%.*]] = cir.alloca !ty_22__va_list22, !cir.ptr, ["c", init] {alignment = 8 : i64} +// BEFORE: cir.store %arg0, [[VAR_LIST]] : !ty_22__va_list22, !cir.ptr +// BEFORE: cir.scope { +// BEFORE-NEXT: [[TMP:%.*]] = cir.va.arg [[VAR_LIST]] : (!cir.ptr) -> !cir.ptr +// BEFORE-NEXT: } +// BEFORE-NEXT: cir.return + +// AFTER: cir.func @f1(%arg0: !ty_22__va_list22) attributes +// AFTER: [[VARLIST:%.*]] = cir.alloca !ty_22__va_list22, !cir.ptr, ["c", init] {alignment = 8 : i64} +// AFTER: cir.store %arg0, [[VARLIST]] : !ty_22__va_list22, !cir.ptr +// AFTER: cir.scope { +// +// AFTER-NEXT: [[GR_OFFS_P:%.*]] = cir.get_member [[VARLIST]][3] {name = "gr_offs"} : !cir.ptr -> !cir.ptr +// AFTER-NEXT: [[GR_OFFS:%.*]] = cir.load [[GR_OFFS_P]] : !cir.ptr +// AFTER: [[ZERO:%.*]] = cir.const #cir.int<0> : !s32i +// AFTER: [[CMP0:%.*]] = cir.cmp(ge, [[GR_OFFS]], [[ZERO]]) : !s32i, !cir.bool +// AFTER-NEXT: cir.brcond [[CMP0]] [[BB_ON_STACK:\^bb.*]], [[BB_MAY_REG:\^bb.*]] + +// This BB calculates to see if it is possible to pass arg in register. +// AFTER: [[BB_MAY_REG]]: +// AFTER-NEXT: [[EIGHT:%.*]] = cir.const #cir.int<8> : !s32i +// AFTER-NEXT: [[NEW_REG_OFFS:%.*]] = cir.binop(add, [[GR_OFFS]], [[EIGHT]]) : !s32i +// AFTER-NEXT: cir.store [[NEW_REG_OFFS]], [[GR_OFFS_P]] : !s32i, !cir.ptr +// AFTER-NEXT: [[CMP1:%.*]] = cir.cmp(le, [[NEW_REG_OFFS]], [[ZERO]]) : !s32i, !cir.bool +// AFTER-NEXT: cir.brcond [[CMP1]] [[BB_IN_REG:\^bb.*]], [[BB_ON_STACK]] + +// arg is passed in register. +// AFTER: [[BB_IN_REG]]: +// AFTER-NEXT: [[GR_TOP_P:%.*]] = cir.get_member [[VARLIST]][1] {name = "gr_top"} : !cir.ptr -> !cir.ptr> +// AFTER-NEXT: [[GR_TOP:%.*]] = cir.load [[GR_TOP_P]] : !cir.ptr>, !cir.ptr +// AFTER-NEXT: [[TMP2:%.*]] = cir.cast(bitcast, [[GR_TOP]] : !cir.ptr), !cir.ptr +// AFTER-NEXT: [[TMP3:%.*]] = cir.ptr_stride([[TMP2]] : !cir.ptr, [[GR_OFFS]] : !s32i), !cir.ptr +// AFTER-NEXT: [[IN_REG_OUTPUT:%.*]] = cir.cast(bitcast, [[TMP3]] : !cir.ptr), !cir.ptr +// AFTER-NEXT: cir.br [[BB_END:\^bb.*]]([[IN_REG_OUTPUT]] : !cir.ptr) + +// arg is passed in stack. +// AFTER: [[BB_ON_STACK]]: +// AFTER-NEXT: [[STACK_P:%.*]] = cir.get_member [[VARLIST]][0] {name = "stack"} : !cir.ptr -> !cir.ptr> +// AFTER-NEXT: [[STACK_V:%.*]] = cir.load [[STACK_P]] : !cir.ptr>, !cir.ptr +// AFTER-NEXT: [[EIGHT_IN_PTR_ARITH:%.*]] = cir.const #cir.int<8> : !u64i +// AFTER-NEXT: [[TMP4:%.*]] = cir.cast(bitcast, [[STACK_V]] : !cir.ptr), !cir.ptr +// AFTER-NEXT: [[TMP5:%.*]] = cir.ptr_stride([[TMP4]] : !cir.ptr, [[EIGHT_IN_PTR_ARITH]] : !u64i), !cir.ptr +// AFTER-NEXT: [[NEW_STACK_V:%.*]] = cir.cast(bitcast, [[TMP5]] : !cir.ptr), !cir.ptr +// AFTER-NEXT: cir.store [[NEW_STACK_V]], [[STACK_P]] : !cir.ptr, !cir.ptr> +// AFTER-NEXT: cir.br [[BB_END]]([[STACK_V]] : !cir.ptr) + +// This BB is where different path converges. BLK_ARG is the arg addr which +// could come from IN_REG block where arg is passed in register, and saved in callee +// stack's argument saving area. +// Or from ON_STACK block which means arg is passed in from caller's stack area. +// AFTER-NEXT: [[BB_END]]([[BLK_ARG:%.*]]: !cir.ptr): // 2 preds: [[BB_IN_REG]], [[BB_ON_STACK]] +// AFTER-NEXT: [[TMP0:%.*]] = cir.cast(bitcast, [[BLK_ARG]] : !cir.ptr), !cir.ptr> +// AFTER-NEXT: [[TMP1:%.*]] = cir.load [[TMP0]] : !cir.ptr>, !cir.ptr +// AFTER-NEXT: cir.yield +// AFTER-NEXT: } +// AFTER-NEXT: cir.return + +// LLVM: %struct.__va_list = type { ptr, ptr, ptr, i32, i32 } +// LLVM: define void @f1(%struct.__va_list %0) +// LLVM: [[VARLIST:%.*]] = alloca %struct.__va_list, i64 1, align 8, +// LLVM: br label %[[SCOPE_FRONT:.*]], + +// LLVM: [[SCOPE_FRONT]]: ; preds = %1 +// LLVM: [[GR_OFFS_P:%.*]] = getelementptr %struct.__va_list, ptr [[VARLIST]], i32 0, i32 3 +// LLVM: [[GR_OFFS:%.*]] = load i32, ptr [[GR_OFFS_P]], align 4, +// LLVM-NEXT: [[CMP0:%.*]] = icmp sge i32 [[GR_OFFS]], 0, +// LLVM-NEXT: br i1 [[CMP0]], label %[[BB_ON_STACK:.*]], label %[[BB_MAY_REG:.*]], + +// LLVM: [[BB_MAY_REG]]: ; +// LLVM: [[NEW_REG_OFFS:%.*]] = add i32 [[GR_OFFS]], 8, +// LLVM: store i32 [[NEW_REG_OFFS]], ptr [[GR_OFFS_P]], align 4, +// LLVM-NEXT: [[CMP1:%.*]] = icmp sle i32 [[NEW_REG_OFFS]], 0, +// LLVM-NEXT: br i1 [[CMP1]], label %[[BB_IN_REG:.*]], label %[[BB_ON_STACK]], + +// LLVM: [[BB_IN_REG]]: ; +// LLVM-NEXT: [[GR_TOP_P:%.*]] = getelementptr %struct.__va_list, ptr [[VARLIST]], i32 0, i32 1, +// LLVM-NEXT: [[GR_TOP:%.*]] = load ptr, ptr [[GR_TOP_P]], align 8, +// LLVM-NEXT: [[EXT64_GR_OFFS:%.*]] = sext i32 [[GR_OFFS]] to i64, +// LLVM-NEXT: [[IN_REG_OUTPUT:%.*]] = getelementptr i8, ptr [[GR_TOP]], i64 [[EXT64_GR_OFFS]], +// LLVM-NEXT: br label %[[BB_END:.*]], + +// LLVM: [[BB_ON_STACK]]: ; +// LLVM-NEXT: [[STACK_P:%.*]] = getelementptr %struct.__va_list, ptr [[VARLIST]], i32 0, i32 0, +// LLVM-NEXT: [[STACK_V:%.*]] = load ptr, ptr [[STACK_P]], align 8, +// LLVM-NEXT: [[NEW_STACK_V:%.*]] = getelementptr i8, ptr [[STACK_V]], i32 8, +// LLVM-NEXT: store ptr [[NEW_STACK_V]], ptr [[STACK_P]], align 8, +// LLVM-NEXT: br label %[[BB_END]], + +// LLVM: [[BB_END]]: ; preds = %[[BB_ON_STACK]], %[[BB_IN_REG]] +// LLVM-NEXT: [[PHIP:%.*]] = phi ptr [ [[IN_REG_OUTPUT]], %[[BB_IN_REG]] ], [ [[STACK_V]], %[[BB_ON_STACK]] ] +// LLVM-NEXT: [[PHIV:%.*]] = load ptr, ptr [[PHIP]], align 8, +// LLVM-NEXT: br label %[[OUT_SCOPE:.*]], + +// LLVM: [[OUT_SCOPE]]: ; preds = %[[BB_END]] +// LLVM-NEXT: ret void, diff --git a/clang/test/CIR/CodeGen/var-arg.c b/clang/test/CIR/CodeGen/var-arg.c index 600396f3f502..ef88074f2137 100644 --- a/clang/test/CIR/CodeGen/var-arg.c +++ b/clang/test/CIR/CodeGen/var-arg.c @@ -36,27 +36,13 @@ int f1(int n, ...) { // AFTER: [[CMP0:%.*]] = cir.cmp(ge, [[GR_OFFS]], [[ZERO]]) : !s32i, !cir.bool // AFTER-NEXT: cir.brcond [[CMP0]] [[BB_ON_STACK:\^bb.*]], [[BB_MAY_REG:\^bb.*]] -// This BB is where different path converges. BLK_ARG is the arg addr which -// could come from IN_REG block where arg is passed in register, and saved in callee -// stack's argument saving area. -// Or from ON_STACK block which means arg is passed in from caller's stack area. -// AFTER-NEXT: [[BB_END:\^bb.*]]([[BLK_ARG:%.*]]: !cir.ptr): // 2 preds: [[BB_IN_REG:\^bb.*]], [[BB_ON_STACK]] -// AFTER-NEXT: [[TMP0:%.*]] = cir.cast(bitcast, [[BLK_ARG]] : !cir.ptr), !cir.ptr -// AFTER-NEXT: [[TMP1:%.*]] = cir.load [[TMP0]] : !cir.ptr, !s32i -// AFTER: cir.store [[TMP1]], [[RESP]] : !s32i, !cir.ptr -// AFTER: cir.va.end [[VARLIST]] : !cir.ptr -// AFTER: [[RES:%.*]] = cir.load [[RESP]] : !cir.ptr, !s32i -// AFTER: cir.store [[RES]], [[RETP]] : !s32i, !cir.ptr -// AFTER: [[RETV:%.*]] = cir.load [[RETP]] : !cir.ptr, !s32i -// AFTER: cir.return [[RETV]] : !s32i - // This BB calculates to see if it is possible to pass arg in register. // AFTER: [[BB_MAY_REG]]: // AFTER-NEXT: [[EIGHT:%.*]] = cir.const #cir.int<8> : !s32i // AFTER-NEXT: [[NEW_REG_OFFS:%.*]] = cir.binop(add, [[GR_OFFS]], [[EIGHT]]) : !s32i // AFTER-NEXT: cir.store [[NEW_REG_OFFS]], [[GR_OFFS_P]] : !s32i, !cir.ptr // AFTER-NEXT: [[CMP1:%.*]] = cir.cmp(le, [[NEW_REG_OFFS]], [[ZERO]]) : !s32i, !cir.bool -// AFTER-NEXT: cir.brcond [[CMP1]] [[BB_IN_REG]], [[BB_ON_STACK]] +// AFTER-NEXT: cir.brcond [[CMP1]] [[BB_IN_REG:\^bb.*]], [[BB_ON_STACK]] // arg is passed in register. // AFTER: [[BB_IN_REG]]: @@ -65,7 +51,7 @@ int f1(int n, ...) { // AFTER-NEXT: [[TMP2:%.*]] = cir.cast(bitcast, [[GR_TOP]] : !cir.ptr), !cir.ptr // AFTER-NEXT: [[TMP3:%.*]] = cir.ptr_stride([[TMP2]] : !cir.ptr, [[GR_OFFS]] : !s32i), !cir.ptr // AFTER-NEXT: [[IN_REG_OUTPUT:%.*]] = cir.cast(bitcast, [[TMP3]] : !cir.ptr), !cir.ptr -// AFTER-NEXT: cir.br [[BB_END]]([[IN_REG_OUTPUT]] : !cir.ptr) +// AFTER-NEXT: cir.br [[BB_END:\^bb.*]]([[IN_REG_OUTPUT]] : !cir.ptr) // arg is passed in stack. // AFTER: [[BB_ON_STACK]]: @@ -78,6 +64,20 @@ int f1(int n, ...) { // AFTER-NEXT: cir.store [[NEW_STACK_V]], [[STACK_P]] : !cir.ptr, !cir.ptr> // AFTER-NEXT: cir.br [[BB_END]]([[STACK_V]] : !cir.ptr) +// This BB is where different path converges. BLK_ARG is the arg addr which +// could come from IN_REG block where arg is passed in register, and saved in callee +// stack's argument saving area. +// Or from ON_STACK block which means arg is passed in from caller's stack area. +// AFTER-NEXT: [[BB_END]]([[BLK_ARG:%.*]]: !cir.ptr): // 2 preds: [[BB_IN_REG]], [[BB_ON_STACK]] +// AFTER-NEXT: [[TMP0:%.*]] = cir.cast(bitcast, [[BLK_ARG]] : !cir.ptr), !cir.ptr +// AFTER-NEXT: [[TMP1:%.*]] = cir.load [[TMP0]] : !cir.ptr, !s32i +// AFTER: cir.store [[TMP1]], [[RESP]] : !s32i, !cir.ptr +// AFTER: cir.va.end [[VARLIST]] : !cir.ptr +// AFTER: [[RES:%.*]] = cir.load [[RESP]] : !cir.ptr, !s32i +// AFTER: cir.store [[RES]], [[RETP]] : !s32i, !cir.ptr +// AFTER: [[RETV:%.*]] = cir.load [[RETP]] : !cir.ptr, !s32i +// AFTER: cir.return [[RETV]] : !s32i + // LLVM: %struct.__va_list = type { ptr, ptr, ptr, i32, i32 } // LLVM: define i32 @f1(i32 %0, ...) // LLVM: [[ARGN:%.*]] = alloca i32, i64 1, align 4, @@ -89,32 +89,32 @@ int f1(int n, ...) { // LLVM-NEXT: [[CMP0:%.*]] = icmp sge i32 [[GR_OFFS]], 0, // LLVM-NEXT: br i1 [[CMP0]], label %[[BB_ON_STACK:.*]], label %[[BB_MAY_REG:.*]], -// LLVM: [[BB_END:.*]]: ; preds = %[[BB_ON_STACK]], %[[BB_IN_REG:.*]] -// LLVM-NEXT: [[PHIP:%.*]] = phi ptr [ [[IN_REG_OUTPUT:%.*]], %[[BB_IN_REG]] ], [ [[STACK_V:%.*]], %[[BB_ON_STACK]] ] -// LLVM-NEXT: [[PHIV:%.*]] = load i32, ptr [[PHIP]], align 4, -// LLVM-NEXT: store i32 [[PHIV]], ptr [[RESP]], align 4, -// LLVM: call void @llvm.va_end.p0(ptr [[VARLIST]]), -// LLVM: [[RES:%.*]] = load i32, ptr [[RESP]], align 4, -// LLVM: store i32 [[RES]], ptr [[RETP]], align 4, -// LLVM: [[RETV:%.*]] = load i32, ptr [[RETP]], align 4, -// LLVM-NEXT: ret i32 [[RETV]], - // LLVM: [[BB_MAY_REG]]: ; // LLVM: [[NEW_REG_OFFS:%.*]] = add i32 [[GR_OFFS]], 8, // LLVM: store i32 [[NEW_REG_OFFS]], ptr [[GR_OFFS_P]], align 4, // LLVM-NEXT: [[CMP1:%.*]] = icmp sle i32 [[NEW_REG_OFFS]], 0, -// LLVM-NEXT: br i1 [[CMP1]], label %[[BB_IN_REG]], label %[[BB_ON_STACK]], +// LLVM-NEXT: br i1 [[CMP1]], label %[[BB_IN_REG:.*]], label %[[BB_ON_STACK]], // LLVM: [[BB_IN_REG]]: ; // LLVM-NEXT: [[GR_TOP_P:%.*]] = getelementptr %struct.__va_list, ptr [[VARLIST]], i32 0, i32 1, // LLVM-NEXT: [[GR_TOP:%.*]] = load ptr, ptr [[GR_TOP_P]], align 8, // LLVM-NEXT: [[EXT64_GR_OFFS:%.*]] = sext i32 [[GR_OFFS]] to i64, -// LLVM-NEXT: [[IN_REG_OUTPUT]] = getelementptr i8, ptr [[GR_TOP]], i64 [[EXT64_GR_OFFS]], -// LLVM-NEXT: br label %[[BB_END]], +// LLVM-NEXT: [[IN_REG_OUTPUT:%.*]] = getelementptr i8, ptr [[GR_TOP]], i64 [[EXT64_GR_OFFS]], +// LLVM-NEXT: br label %[[BB_END:.*]], // LLVM: [[BB_ON_STACK]]: ; // LLVM-NEXT: [[STACK_P:%.*]] = getelementptr %struct.__va_list, ptr [[VARLIST]], i32 0, i32 0, -// LLVM-NEXT: [[STACK_V]] = load ptr, ptr [[STACK_P]], align 8, +// LLVM-NEXT: [[STACK_V:%.*]] = load ptr, ptr [[STACK_P]], align 8, // LLVM-NEXT: [[NEW_STACK_V:%.*]] = getelementptr i8, ptr [[STACK_V]], i32 8, // LLVM-NEXT: store ptr [[NEW_STACK_V]], ptr [[STACK_P]], align 8, // LLVM-NEXT: br label %[[BB_END]], + +// LLVM: [[BB_END]]: ; preds = %[[BB_ON_STACK]], %[[BB_IN_REG]] +// LLVM-NEXT: [[PHIP:%.*]] = phi ptr [ [[IN_REG_OUTPUT]], %[[BB_IN_REG]] ], [ [[STACK_V]], %[[BB_ON_STACK]] ] +// LLVM-NEXT: [[PHIV:%.*]] = load i32, ptr [[PHIP]], align 4, +// LLVM-NEXT: store i32 [[PHIV]], ptr [[RESP]], align 4, +// LLVM: call void @llvm.va_end.p0(ptr [[VARLIST]]), +// LLVM: [[RES:%.*]] = load i32, ptr [[RESP]], align 4, +// LLVM: store i32 [[RES]], ptr [[RETP]], align 4, +// LLVM: [[RETV:%.*]] = load i32, ptr [[RETP]], align 4, +// LLVM-NEXT: ret i32 [[RETV]],