Skip to content

Commit

Permalink
[CIR][LowerToLLVM][CXXABI] Fix basic block ordering issue. (llvm#676)
Browse files Browse the repository at this point in the history
When loweringPrepare cg.var_arg for AArch64, we create multiple basic
blocks, but didn't really get ordering of the blocks in the blocklist of
the parent region right. That is, we didn't make sure the last of the
block list is the naturally last block (exit) of the region. This PR
fixes this problem.

If we don't fix this problem, FlattenCFGPass will fail verification
because CIRScopeOpFlattening in this pass is onlyy expecting to see
cir.yield op in the last block of the region's block list.
  • Loading branch information
ghehg authored and lanza committed Oct 12, 2024
1 parent 421d972 commit 7abde0a
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
54 changes: 26 additions & 28 deletions clang/test/CIR/CodeGen/var-arg-float.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,24 +39,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<!void>): // 2 preds: [[BB_IN_REG:\^bb.*]], [[BB_ON_STACK]]
// AFTER-NEXT: [[TMP0:%.*]] = cir.cast(bitcast, [[BLK_ARG]] : !cir.ptr<!void>), !cir.ptr<!cir.double>
// AFTER-NEXT: [[TMP1:%.*]] = cir.load [[TMP0]] : !cir.ptr<!cir.double>, !cir.double
// AFTER: cir.store [[TMP1]], [[RESP]] : !cir.double, !cir.ptr<!cir.double>
// AFTER: cir.va.end [[VARLIST]] : !cir.ptr<!ty_22__va_list22>
// AFTER: [[RES:%.*]] = cir.load [[RESP]] : !cir.ptr<!cir.double>, !cir.double
// AFTER: cir.store [[RES]], [[RETP]] : !cir.double, !cir.ptr<!cir.double>
// AFTER: [[RETV:%.*]] = cir.load [[RETP]] : !cir.ptr<!cir.double>, !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<!s32i>
// 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]]:
Expand All @@ -65,7 +53,7 @@ double f1(int n, ...) {
// AFTER-NEXT: [[TMP2:%.*]] = cir.cast(bitcast, [[VR_TOP]] : !cir.ptr<!void>), !cir.ptr<i8>
// AFTER-NEXT: [[TMP3:%.*]] = cir.ptr_stride([[TMP2]] : !cir.ptr<i8>, [[VR_OFFS]] : !s32i), !cir.ptr<i8>
// AFTER-NEXT: [[IN_REG_OUTPUT:%.*]] = cir.cast(bitcast, [[TMP3]] : !cir.ptr<i8>), !cir.ptr<!void>
// AFTER-NEXT: cir.br [[BB_END]]([[IN_REG_OUTPUT]] : !cir.ptr<!void>)
// AFTER-NEXT: cir.br [[BB_END:\^bb.*]]([[IN_REG_OUTPUT]] : !cir.ptr<!void>)


// AFTER: [[BB_ON_STACK]]:
Expand All @@ -78,6 +66,16 @@ double f1(int n, ...) {
// AFTER-NEXT: cir.store [[NEW_STACK_V]], [[STACK_P]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
// AFTER-NEXT: cir.br [[BB_END]]([[STACK_V]] : !cir.ptr<!void>)

// AFTER-NEXT: [[BB_END]]([[BLK_ARG:%.*]]: !cir.ptr<!void>): // 2 preds: [[BB_IN_REG]], [[BB_ON_STACK]]
// AFTER-NEXT: [[TMP0:%.*]] = cir.cast(bitcast, [[BLK_ARG]] : !cir.ptr<!void>), !cir.ptr<!cir.double>
// AFTER-NEXT: [[TMP1:%.*]] = cir.load [[TMP0]] : !cir.ptr<!cir.double>, !cir.double
// AFTER: cir.store [[TMP1]], [[RESP]] : !cir.double, !cir.ptr<!cir.double>
// AFTER: cir.va.end [[VARLIST]] : !cir.ptr<!ty_22__va_list22>
// AFTER: [[RES:%.*]] = cir.load [[RESP]] : !cir.ptr<!cir.double>, !cir.double
// AFTER: cir.store [[RES]], [[RETP]] : !cir.double, !cir.ptr<!cir.double>
// AFTER: [[RETV:%.*]] = cir.load [[RETP]] : !cir.ptr<!cir.double>, !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, ...)
Expand All @@ -90,32 +88,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]],
106 changes: 106 additions & 0 deletions clang/test/CIR/CodeGen/var-arg-scope.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// 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
// XFAIL: *

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<!ty_22__va_list22>, ["c", init] {alignment = 8 : i64}
// BEFORE: cir.store %arg0, [[VAR_LIST]] : !ty_22__va_list22, !cir.ptr<!ty_22__va_list22>
// BEFORE: cir.scope {
// BEFORE-NEXT: [[TMP:%.*]] = cir.va.arg [[VAR_LIST]] : (!cir.ptr<!ty_22__va_list22>) -> !cir.ptr<!void>
// 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<!ty_22__va_list22>, ["c", init] {alignment = 8 : i64}
// AFTER: cir.store %arg0, [[VARLIST]] : !ty_22__va_list22, !cir.ptr<!ty_22__va_list22>
// AFTER: cir.scope {
//
// AFTER-NEXT: [[GR_OFFS_P:%.*]] = cir.get_member [[VARLIST]][3] {name = "gr_offs"} : !cir.ptr<!ty_22__va_list22> -> !cir.ptr<!s32i>
// AFTER-NEXT: [[GR_OFFS:%.*]] = cir.load [[GR_OFFS_P]] : !cir.ptr<!s32i>
// 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<!s32i>
// 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<!ty_22__va_list22> -> !cir.ptr<!cir.ptr<!void>>
// AFTER-NEXT: [[GR_TOP:%.*]] = cir.load [[GR_TOP_P]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
// AFTER-NEXT: [[TMP2:%.*]] = cir.cast(bitcast, [[GR_TOP]] : !cir.ptr<!void>), !cir.ptr<i8>
// AFTER-NEXT: [[TMP3:%.*]] = cir.ptr_stride([[TMP2]] : !cir.ptr<i8>, [[GR_OFFS]] : !s32i), !cir.ptr<i8>
// AFTER-NEXT: [[IN_REG_OUTPUT:%.*]] = cir.cast(bitcast, [[TMP3]] : !cir.ptr<i8>), !cir.ptr<!void>
// AFTER-NEXT: cir.br [[BB_END:\^bb.*]]([[IN_REG_OUTPUT]] : !cir.ptr<!void>)

// arg is passed in stack.
// AFTER: [[BB_ON_STACK]]:
// AFTER-NEXT: [[STACK_P:%.*]] = cir.get_member [[VARLIST]][0] {name = "stack"} : !cir.ptr<!ty_22__va_list22> -> !cir.ptr<!cir.ptr<!void>>
// AFTER-NEXT: [[STACK_V:%.*]] = cir.load [[STACK_P]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
// AFTER-NEXT: [[EIGHT_IN_PTR_ARITH:%.*]] = cir.const #cir.int<8> : !u64i
// AFTER-NEXT: [[TMP4:%.*]] = cir.cast(bitcast, [[STACK_V]] : !cir.ptr<!void>), !cir.ptr<i8>
// AFTER-NEXT: [[TMP5:%.*]] = cir.ptr_stride([[TMP4]] : !cir.ptr<i8>, [[EIGHT_IN_PTR_ARITH]] : !u64i), !cir.ptr<i8>
// AFTER-NEXT: [[NEW_STACK_V:%.*]] = cir.cast(bitcast, [[TMP5]] : !cir.ptr<i8>), !cir.ptr<!void>
// AFTER-NEXT: cir.store [[NEW_STACK_V]], [[STACK_P]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
// AFTER-NEXT: cir.br [[BB_END]]([[STACK_V]] : !cir.ptr<!void>)

// 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<!void>): // 2 preds: [[BB_IN_REG]], [[BB_ON_STACK]]
// AFTER-NEXT: [[TMP0:%.*]] = cir.cast(bitcast, [[BLK_ARG]] : !cir.ptr<!void>), !cir.ptr<!cir.ptr<!void>>
// AFTER-NEXT: [[TMP1:%.*]] = cir.load [[TMP0]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
// 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,
60 changes: 30 additions & 30 deletions clang/test/CIR/CodeGen/var-arg.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,27 +38,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<!void>): // 2 preds: [[BB_IN_REG:\^bb.*]], [[BB_ON_STACK]]
// AFTER-NEXT: [[TMP0:%.*]] = cir.cast(bitcast, [[BLK_ARG]] : !cir.ptr<!void>), !cir.ptr<!s32i>
// AFTER-NEXT: [[TMP1:%.*]] = cir.load [[TMP0]] : !cir.ptr<!s32i>, !s32i
// AFTER: cir.store [[TMP1]], [[RESP]] : !s32i, !cir.ptr<!s32i>
// AFTER: cir.va.end [[VARLIST]] : !cir.ptr<!ty_22__va_list22>
// AFTER: [[RES:%.*]] = cir.load [[RESP]] : !cir.ptr<!s32i>, !s32i
// AFTER: cir.store [[RES]], [[RETP]] : !s32i, !cir.ptr<!s32i>
// AFTER: [[RETV:%.*]] = cir.load [[RETP]] : !cir.ptr<!s32i>, !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<!s32i>
// 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]]:
Expand All @@ -67,7 +53,7 @@ int f1(int n, ...) {
// AFTER-NEXT: [[TMP2:%.*]] = cir.cast(bitcast, [[GR_TOP]] : !cir.ptr<!void>), !cir.ptr<i8>
// AFTER-NEXT: [[TMP3:%.*]] = cir.ptr_stride([[TMP2]] : !cir.ptr<i8>, [[GR_OFFS]] : !s32i), !cir.ptr<i8>
// AFTER-NEXT: [[IN_REG_OUTPUT:%.*]] = cir.cast(bitcast, [[TMP3]] : !cir.ptr<i8>), !cir.ptr<!void>
// AFTER-NEXT: cir.br [[BB_END]]([[IN_REG_OUTPUT]] : !cir.ptr<!void>)
// AFTER-NEXT: cir.br [[BB_END:\^bb.*]]([[IN_REG_OUTPUT]] : !cir.ptr<!void>)

// arg is passed in stack.
// AFTER: [[BB_ON_STACK]]:
Expand All @@ -80,6 +66,20 @@ int f1(int n, ...) {
// AFTER-NEXT: cir.store [[NEW_STACK_V]], [[STACK_P]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
// AFTER-NEXT: cir.br [[BB_END]]([[STACK_V]] : !cir.ptr<!void>)

// 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<!void>): // 2 preds: [[BB_IN_REG]], [[BB_ON_STACK]]
// AFTER-NEXT: [[TMP0:%.*]] = cir.cast(bitcast, [[BLK_ARG]] : !cir.ptr<!void>), !cir.ptr<!s32i>
// AFTER-NEXT: [[TMP1:%.*]] = cir.load [[TMP0]] : !cir.ptr<!s32i>, !s32i
// AFTER: cir.store [[TMP1]], [[RESP]] : !s32i, !cir.ptr<!s32i>
// AFTER: cir.va.end [[VARLIST]] : !cir.ptr<!ty_22__va_list22>
// AFTER: [[RES:%.*]] = cir.load [[RESP]] : !cir.ptr<!s32i>, !s32i
// AFTER: cir.store [[RES]], [[RETP]] : !s32i, !cir.ptr<!s32i>
// AFTER: [[RETV:%.*]] = cir.load [[RETP]] : !cir.ptr<!s32i>, !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,
Expand All @@ -91,32 +91,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]],

0 comments on commit 7abde0a

Please sign in to comment.